PHP Singleton design pattern inheritance error

2019-02-22 05:16发布

问题:

From php singleton class below

<?php
class Singleton
{
    /**
     * @var Singleton The reference to *Singleton* instance of this class
     */
    private static $instance;

    /**
     * Returns the *Singleton* instance of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }
}

I am trying to inherit new child class

class SingletonChild extends Singleton {
}

but when I do testing

$obj = Singleton::getInstance();
$obj_two = SingletonChild::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)
var_dump($obj === $obj_two);   // false

I'm getting php fatal error.

PHP Fatal error: Uncaught Error: Cannot access property SingletonChild::$instance

回答1:

Inheriting Singleton class in PHP is difficult, event in PHP 7.0, but you can do this with some changes on your class to work.

first make your Singleton class to abstract

abstract class Singleton {

}

change your $instance variable to array $instance(s)

private $instances = [];

Now change getInstance() method like below

public static function getInstance() {
  if (!isset(self::$instances[static::class]) {
    self::$instances[static::class] = new static();
  }

  return self::$instances[static::class];
}

And change your test

remember now you can't call Singleton:: getInstance() due to abstract

class SingletonChild extends Singleton {
}

class SingletonChildTwo extends SingletonChild {
}

$obj = SingletonChild::getInstance();
$obj_two = SingletonChildTwo::getInstance();
var_dump($obj === SingletonChild::getInstance()); // true
var_dump($obj === $obj_two); // will -> false


回答2:

You made $instance private, which means it cannot be inherited. Change it to protected

protected static $instance;

The manual discusses the individual uses of visibility

http://php.net/manual/en/language.oop5.visibility.php

So it looks like the hangup is in your edit

$obj = Singleton::getInstance();
$obj_two = SingletonChild::getInstance();
var_dump($obj === $obj_two);   // false

This will never be true. getInstance gets an instance of the current class. Since they are different classes they are not the same. Doing a test like this is sloppy, however. I would never do a test on an object like this. What would make more sense is to make sure that you're getting an instance of Singleton which can be done very easily like so

if($obj_two instanceof Singleton) // true

Because the child inherits the parent, it is an instance of the parent



回答3:

You should write:-

if (NULL == self::$instance) {
    self::$instance = new self();
}
return self::$instance;

You do not need to create child class of Singleton class. You can simply use below syntax to get object of Singleton class.

 Singleton::getInstance();

Simply define a method in any class which call Singleton::getInstance(); and return the object.

Check this link for more detail.