Static classes in PHP via abstract keyword?

后端 未结 10 1972
孤独总比滥情好
孤独总比滥情好 2021-01-31 19:00

According to the PHP manual, a class like this:

abstract class Example {}

cannot be instantiated. If I need a class without instance, e.g. for

10条回答
  •  星月不相逢
    2021-01-31 19:52

    What you describe is permitted by the PHP language, but it's not the intended usage of an abstract class. I wouldn't use static methods of an abstract class.

    Here's the downside of doing that: Another developer could extend your abstract class and then instantiate an object, which is what you want to avoid. Example:

    class MyRegistry extends AbstractRegistry { }
    $reg = new MyRegistry();
    

    True, you only need to worry about this if you're handing off your abstract class to another developer who won't comply with your intended usage, but that's why you would make the class a singleton too. An uncooperative developer can override a private constructor:

    class Registry
    {
      private function __construct() { }
    }
    
    class MyRegistry extends Registry
    {
      public function __construct() { } // change private to public
    }
    

    If you were using this class yourself, you would simply remember not to instantiate the class. Then you wouldn't need either mechanism to prevent it. So since you're designing this to be used by others, you need some way to prevent those people from circumventing your intended usage.

    So I offer these two possible alternatives:

    1. Stick with the singleton pattern and make sure the constructor is also final so no one can extend your class and change the constructor to non-private:

      class Registry
      {
        private final function __construct() {
        }
      }
      
    2. Make your Registry support both static and object usage:

      class Registry
      {
        protected static $reg = null;
      
        public static function getInstance() {
          if (self::$reg === null) {
            self::$reg = new Registry();
          }
          return self::$reg;
        }
      }
      

      Then you can call Registry::getInstance() statically, or you can call new Registry() if you want an object instance.

      Then you can do nifty things like store a new registry instance inside your global registry! :-)

      I implemented this as part of Zend Framework, in Zend_Registry

提交回复
热议问题