Extending singletons in PHP

前端 未结 6 578
春和景丽
春和景丽 2021-01-30 11:28

I\'m working in a web app framework, and part of it consists of a number of services, all implemented as singletons. They all extend a Service class, where the singleton behavio

相关标签:
6条回答
  • 2021-01-30 11:47

    This is fixed Johan's answer. PHP 5.3+

    abstract class Singleton
    {
        protected function __construct() {}
        final protected function __clone() {}
    
        final public static function getInstance()
        {
            static $instance = null;
    
            if (null === $instance)
            {
                $instance = new static();
            }
    
            return $instance;
        }
    }
    
    0 讨论(0)
  • 2021-01-30 11:50

    Use trait instead of a abstract class allows to extend a singleton class.

    Use the trait SingletonBase for a parent singleton class.

    Use the trait SingletonChild for its singleton childs.

    interface Singleton
    {
    
        public static function getInstance(): Singleton;
    
    }
    
    trait SingletonBase
    {
    
        private static $instance=null;
    
        abstract protected function __construct();
    
        public static function getInstance(): Singleton {
    
           if (is_null(self::$instance)) {
    
              self::$instance=new static();
    
           }
    
           return self::$instance;
    
        } 
    
        protected function clearInstance(): void {
    
            self::$instance=null;
    
        }
    
        public function __clone()/*: void*/ {
    
            trigger_error('Class singleton '.get_class($this).' cant be cloned.');
        }
    
        public function __wakeup(): void {
    
            trigger_error('Classe singleton '.get_class($this).' cant be serialized.');
    
        }
    
    }
    
    trait SingletonChild
    {
    
        use SingletonBase;
    
    }
    
    class Bar
    {
    
        protected function __construct(){
    
        }
    
    }
    
    class Foo extends Bar implements Singleton
    {
    
          use SingletonBase;
    
    }
    
    class FooChild extends Foo implements Singleton
    {
    
          use SingletonChild; // necessary! If not, the unique instance of FooChild will be the same as the unique instance of its parent Foo
    
    }
    
    0 讨论(0)
  • 2021-01-30 11:57

    Code:

    abstract class Singleton
    {
        protected function __construct()
        {
        }
    
        final public static function getInstance()
        {
            static $instances = array();
    
            $calledClass = get_called_class();
    
            if (!isset($instances[$calledClass]))
            {
                $instances[$calledClass] = new $calledClass();
            }
    
            return $instances[$calledClass];
        }
    
        final private function __clone()
        {
        }
    }
    
    class FileService extends Singleton
    {
        // Lots of neat stuff in here
    }
    
    $fs = FileService::getInstance();
    

    If you use PHP < 5.3, add this too:

    // get_called_class() is only in PHP >= 5.3.
    if (!function_exists('get_called_class'))
    {
        function get_called_class()
        {
            $bt = debug_backtrace();
            $l = 0;
            do
            {
                $l++;
                $lines = file($bt[$l]['file']);
                $callerLine = $lines[$bt[$l]['line']-1];
                preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/', $callerLine, $matches);
            } while ($matches[1] === 'parent' && $matches[1]);
    
            return $matches[1];
        }
    }
    
    0 讨论(0)
  • 2021-01-30 12:01

    Had I paid more attention in 5.3 class, I would have known how to solve this myself. Using the new late static binding feature of PHP 5.3, I believe Coronatus' proposition can be simplified into this:

    class Singleton {
        protected static $instance;
    
        protected function __construct() { }
    
        final public static function getInstance() {
            if (!isset(static::$instance)) {
                static::$instance = new static();
            }
    
            return static::$instance;
        }
    
        final private function __clone() { }
    }
    

    I tried it out, and it works like a charm. Pre 5.3 is still a whole different story, though.

    0 讨论(0)
  • 2021-01-30 12:01
        private static $_instances = [];
    
        /**
         * gets the instance via lazy initialization (created on first usage).
         */
        public static function getInstance():self
        {
            $calledClass = class_basename(static::class);
    
            if (isset(self::$_instances[$calledClass])) {
                self::$_instances[$calledClass] = new static();
            }
    
            return self::$_instances[$calledClass];
        }
    

    The only issue with this one is, if you have the same name Singletons.

    0 讨论(0)
  • 2021-01-30 12:03

    I have found a good solution.

    the following is my code

    abstract class Singleton
    {
        protected static $instance; // must be protected static property ,since we must use static::$instance, private property will be error
    
        private function __construct(){} //must be private !!! [very important],otherwise we can create new father instance in it's Child class 
    
        final protected function __clone(){} #restrict clone
    
        public static function getInstance()
        {
            #must use static::$instance ,can not use self::$instance,self::$instance will always be Father's static property 
            if (! static::$instance instanceof static) {
                static::$instance = new static();
            }
            return static::$instance;
        }
    }
    
    class A extends Singleton
    {
       protected static $instance; #must redefined property
    }
    
    class B extends A
    {
        protected static $instance;
    }
    
    $a = A::getInstance();
    $b = B::getInstance();
    $c = B::getInstance();
    $d = A::getInstance();
    $e = A::getInstance();
    echo "-------";
    
    var_dump($a,$b,$c,$d,$e);
    
    #object(A)#1 (0) { }
    #object(B)#2 (0) { } 
    #object(B)#2 (0) { } 
    #object(A)#1 (0) { } 
    #object(A)#1 (0) { }
    

    You can refer http://php.net/manual/en/language.oop5.late-static-bindings.php for more info

    0 讨论(0)
提交回复
热议问题