Il tuo esempio è già imperfetto, in quanto Admin
acquisisce nuove proprietà rispetto alla classe base che lo rende incompatibile. Sarebbe stato più intelligente posizionare subito la proprietà $permissions
nella classe base.
Chiediti, in quali casi potrebbe essere opportuno introdurre nuove proprietà su un oggetto esistente?
Sia l'istanziazione di un oggetto come un'istanza di una classe specifica o l'utilizzo di una fabbrica con l'hint di tipo appropriato garantisce che l'oggetto generato abbia proprietà e interfacce specifiche e il comportamento di ogni singola interfaccia sia costante per tutta la durata del oggetto.
Promuovendo l'oggetto in una classe diversa durante il live time, stai violando questa promessa, rendendo difficile tracciare quale implementazione il tuo codice sta effettivamente utilizzando nel corso della sua vita.
Crea anche un altro problema, se scegli di estendere dinamicamente il tuo oggetto durante il runtime, non c'è modo di tornare indietro per scegliere un diverso affinamento. Ogni interfaccia che si aspetta che il tuo oggetto abbia, dovrebbe quindi essere già presente alla creazione.
Se, come nel tuo esempio, hai un caso in cui un caso speciale di una classe è più avanzato in un solo aspetto, considera di scaricare tale comportamento in una classe separata. Nel tuo caso:
class User {
private $permission;
private $name
public function __construct($name, Permission $permission){
$this->name = $name;
$this->permission = $permission;
}
public function changePermissionModell(Permission $permission) {
$this->permission = $permission;
}
}
interface Permission {
public function checkPermission($scope);
}
class ACLPermission implements Permission {
public function checkPermission($scope) {
return ACL::checkPermission($scope);
}
}
class RootPermission implements Permission {
public function checkPermission($scope) {
return true;
}
}
$defaultPermission = new ACLPermission();
$user = new User("Tom", $defaultPermission);
// Promote "Tom" to admin
$user->changePermissionModell(new RootPermission());