Search code examples
phpfactorybase-class

Blocking the possibility to create classes directly bypassing a factory


In a base class for all the models in our MVC system, I created a factory method BaseCLass::getNew() that returns an instance of the requested child class when called via SomeChildClass::getNew().

Now, I'm looking for a way to force the programmer to use this factory. I.e., idially I'd like that any class created directly, like this:

 new SomeChildClass

will throw an exception upon creation, and only classes created by the factory will be usable.

Any ideas how can this be achieved?

Our code is written in PHP, but good chance that your idea will be valuable even if you think on a different language.

edit: I cannot make my constructor private, as the framework constructor in the class that I inherit is public, and php would not allow me this.


Solution

  • By making the class have a private constructor.

    Update -- solution that covers your stated requirements

    class Base {
        private static $constructorToken = null;
    
        protected static function getConstructorToken() {
            if (self::$constructorToken === null) {
                self::$constructorToken = new stdClass;
            }
    
            return self::$constructorToken;
        }
    }
    
    class Derived extends Base {
        public function __construct($token) {
            if ($token !== parent::getConstructorToken()) {
                die ("Attempted to construct manually");
            }
        }
    
        public static function makeMeOne() {
            return new Derived(parent::getConstructorToken());
        }
    }
    

    This solution takes advantage of the object equality rules for stdClass by storing a "magic password" object on the base class which only derived classes can access. You can tweak it to taste.

    I wouldn't call it horrible like the debug_backtrace idea, but still I have the impression that things should be done differently.