Creating the Singleton design pattern in PHP5

前端 未结 21 1841
猫巷女王i
猫巷女王i 2020-11-22 04:21

How would one create a Singleton class using PHP5 classes?

相关标签:
21条回答
  • 2020-11-22 04:59

    The Real One and Modern way to make Singleton Pattern is:

    <?php
    
    /**
     * Singleton Pattern.
     * 
     * Modern implementation.
     */
    class Singleton
    {
        /**
         * Call this method to get singleton
         */
        public static function instance()
        {
          static $instance = false;
          if( $instance === false )
          {
            // Late static binding (PHP 5.3+)
            $instance = new static();
          }
    
          return $instance;
        }
    
        /**
         * Make constructor private, so nobody can call "new Class".
         */
        private function __construct() {}
    
        /**
         * Make clone magic method private, so nobody can clone instance.
         */
        private function __clone() {}
    
        /**
         * Make sleep magic method private, so nobody can serialize instance.
         */
        private function __sleep() {}
    
        /**
         * Make wakeup magic method private, so nobody can unserialize instance.
         */
        private function __wakeup() {}
    
    }
    

    So now you can use it like.

    <?php
    
    /**
     * Database.
     *
     * Inherited from Singleton, so it's now got singleton behavior.
     */
    class Database extends Singleton {
    
      protected $label;
    
      /**
       * Example of that singleton is working correctly.
       */
      public function setLabel($label)
      {
        $this->label = $label;
      }
    
      public function getLabel()
      {
        return $this->label;
      }
    
    }
    
    // create first instance
    $database = Database::instance();
    $database->setLabel('Abraham');
    echo $database->getLabel() . PHP_EOL;
    
    // now try to create other instance as well
    $other_db = Database::instance();
    echo $other_db->getLabel() . PHP_EOL; // Abraham
    
    $other_db->setLabel('Priler');
    echo $database->getLabel() . PHP_EOL; // Priler
    echo $other_db->getLabel() . PHP_EOL; // Priler
    

    As you see this realization is lot more flexible.

    0 讨论(0)
  • 2020-11-22 05:02
    class Database{
    
            //variable to hold db connection
            private $db;
            //note we used static variable,beacuse an instance cannot be used to refer this
            public static $instance;
    
            //note constructor is private so that classcannot be instantiated
            private function __construct(){
              //code connect to database  
    
             }     
    
             //to prevent loop hole in PHP so that the class cannot be cloned
            private function __clone() {}
    
            //used static function so that, this can be called from other classes
            public static function getInstance(){
    
                if( !(self::$instance instanceof self) ){
                    self::$instance = new self();           
                }
                 return self::$instance;
            }
    
    
            public function query($sql){
                //code to run the query
            }
    
        }
    
    
    Access the method getInstance using
    $db = Singleton::getInstance();
    $db->query();
    
    0 讨论(0)
  • 2020-11-22 05:04

    I liked @jose-segura method of using traits but didn't like the need to define a static variable on sub-classes. Below is a solution that avoids it by caching the instances in a static local variable to the factory method indexed by class name:

    <?php
    trait Singleton {
    
      # Single point of entry for creating a new instance. For a given
      # class always returns the same instance.
      public static function instance(){
        static $instances = array();
        $class = get_called_class();
        if( !isset($instances[$class]) ) $instances[$class] = new $class();
        return $instances[$class];
      }
    
      # Kill traditional methods of creating new instances
      protected function __clone() {}
      protected function __construct() {}
    }
    

    Usage is the same as @jose-segura only no need for the static variable in sub-classes.

    0 讨论(0)
  • 2020-11-22 05:05

    Here's my example that provides ability to call as $var = new Singleton() and also creating 3 variables to test if it creates new object:

    class Singleton{
    
        private static $data;
    
        function __construct(){
            if ($this::$data == null){
                $this->makeSingleton();
            }
            echo "<br/>".$this::$data;
        }
    
        private function makeSingleton(){
            $this::$data = rand(0, 100);
        }
    
        public function change($new_val){
            $this::$data = $new_val;
        }
    
        public function printme(){
            echo "<br/>".$this::$data;
        }
    
    }
    
    
    $a = new Singleton();
    $b = new Singleton();
    $c = new Singleton();
    
    $a->change(-2);
    $a->printme();
    $b->printme();
    
    $d = new Singleton();
    $d->printme();
    
    0 讨论(0)
  • 2020-11-22 05:07

    Unfortunately Inwdr's answer breaks when there are multiple subclasses.

    Here is a correct inheritable Singleton base class.

    class Singleton
    {
        private static $instances = array();
        protected function __construct() {}
        protected function __clone() {}
        public function __wakeup()
        {
            throw new Exception("Cannot unserialize singleton");
        }
    
        public static function getInstance()
        {
            $cls = get_called_class(); // late-static-bound class name
            if (!isset(self::$instances[$cls])) {
                self::$instances[$cls] = new static;
            }
            return self::$instances[$cls];
        }
    }
    

    Test code:

    class Foo extends Singleton {}
    class Bar extends Singleton {}
    
    echo get_class(Foo::getInstance()) . "\n";
    echo get_class(Bar::getInstance()) . "\n";
    
    0 讨论(0)
  • 2020-11-22 05:08

    All this complexity ("late static binding" ... harumph) is, to me, simply a sign of PHP's broken object/class model. If class objects were first-class objects (see Python), then "$_instance" would be a class instance variable -- a member of the class object, as opposed to a member/property of its instances, and also as opposed to shared by its descendants. In the Smalltalk world, this is the difference between a "class variable" and a "class instance variable".

    In PHP, it looks to me as though we need to take to heart the guidance that patterns are a guide towards writing code -- we might perhaps think about a Singleton template, but trying to write code that inherits from an actual "Singleton" class looks misguided for PHP (though I supposed some enterprising soul could create a suitable SVN keyword).

    I will continue to just code each singleton separately, using a shared template.

    Notice that I'm absolutely staying OUT of the singletons-are-evil discussion, life is too short.

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