0

I cannot find information on this anywhere so I assume it doesn't exist.

It makes much sense for me for such functionality to exist and I want to ask whether it actually does and I am wrong in my assumption, or is there any good reasons it does not and why I should not attempt to create it.

class User {
    public $name;
    public function __construct($name){
        $this->name = $name;
    }
}

class Admin extends User {
    private $permissions = 0777; // dumb example
}

$user = new User('Tom');

// we decide tom should be an admin
$user->upgrade('\Admin');

get_class($user); // returns "Admin"

Eventually this will also eliminate the need of factories.

4

Your example is already flawed, as Admin gains new properties over the base class which makes it incompatible. It would have been smarter to place the $permissions property straight away in the base class.

Ask yourself, in what cases could it be desirable to introduce new properties on an existing object?

Both instantiating an object as an instance of a specific class or using a factory with proper type hinting gives you a guarantee that your generated object has specific properties and interfaces, and the behavior of each single interface is constant over the lifetime of the object.

By promoting the object to a different class during live time, you are violating that promise, making it hard to trace which implementation your code is actually using over the course of its lifetime.

It also creates another problem, if you choose to dynamically extend your object during runtime, there is no way of going back to choose a different refinement. Each interface you are expecting your object to have, should therefor already be present at creation.

If, like in your example, you have a case where a special case of a class is more advanced in only a single aspect, consider offloading that behavior into a separate class. In your case:

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());
  • I too believe that the Strategy Pattern with a Permission interface is the better solution here. However, specializing a User to an Admin is type-safe since Admin extends User. Therefore, all type hints would still be valid and no static guarantees are violated, as long as this type hierarchy uses proper subtyping according to the Liskov Substitution Principle. Some very dynamic languages such as Perl can change an object's class after construction (example), but that feature is rarely used. – amon Apr 13 '15 at 10:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.