开发者

Creating a Singleton base class in PHP 5.3

开发者 https://www.devze.com 2023-01-21 14:07 出处:网络
Straight to the point: I\'ve got two singleton classes, both inheriting their single开发者_运维问答ton nature from a super-class. I initialize some properties on the first singleton, and then have the

Straight to the point: I've got two singleton classes, both inheriting their single开发者_运维问答ton nature from a super-class. I initialize some properties on the first singleton, and then have the second singleton retrieve the instance of the first one. That instance, however, does not seem to be the one I initialized in the first place. Some example code might help to explain this:

First, the super-class, providing singleton nature (requires PHP 5.3 or greater):

class Singleton {

    protected static $instance;

    protected function __construct() { }

    final private function __clone() { }

    public static function getInstance() {
        if (!(static::$instance instanceof static)) {
            static::$instance = new static();
        }
        return static::$instance;
    }

}

Then we've got the the first singleton carrying a value:

require_once('Singleton.php');

class SingletonA extends Singleton {

    protected $value;

    public function SingletonA() {
        $this->value = false;
    }

    public function getValue() {
        return $this->value;
    }

    public function setValue($value) {
        $this->value = $value;
    }

}

Then the second singleton that references the first singleton:

require_once('Singleton.php');
require_once('SingletonA.php');

class SingletonB extends Singleton {

    public function getValue() {
        return SingletonA::getInstance()->getValue();
    }

}

Now for the test that shows how this fails:

require_once('SingletonA.php');
require_once('SingletonB.php');

SingletonA::getInstance()->setValue(true);

echo (SingletonA::getInstance()->getValue()) ? "true\n" : "false\n";
echo (SingletonB::getInstance()->getValue()) ? "true\n" : "false\n";

The test yields the following output:

true
false

Clearly, the SingletonA instance that the test code references is not the same instance that the SingletonB instance references. In short, SingletonA is not as single as I need it to be. How is this possible? And what magic can I wield to remedy this behaviour, giving me a true singleton?


Try using isset rather than instanceof:

class Singleton {
    protected static $instances;

    protected function __construct() { }

    final private function __clone() { }

    public static function getInstance() {
        $class = get_called_class();

        if (!isset(self::$instances[$class])) {
            self::$instances[$class] = new $class;
        }
        return self::$instances[$class];
    }
}


SingletonA and SingletonB are different classes. Although they inherit from the same class, they are separate classes and so they have different static instances.

If you change your code to get 2 instances of SingletonA or 2 instances of SingletonB, you will see the behavior you expect. But because they are different classes, they are not the same singleton.


I'm pretty sure it's because you are using static methods, which are not instanced.


Let's talk OO. :)

SingletonA and SingletonB are of type Singleton

thus it can be said:

SingletonA is Singleton

and

SingletonB is Singleton

i.e. they're both Singleton

The expected meaning of Singleton means there can be only one. Many people from an OO background using your code will be confused.

Usually, implementation of Singleton would be on a per class basis because most OO languages will not be bent to allow the intent of what you are proposing.

That PHP might do (via get_called_class() magic) doesn't mean it should.

I can absolutely accept that from a utilitarian point of view, the accepted answer looks good. Given the niftyness of the accepted answer, I'd propose a name change that doesn't conflict with "standard" Singleton implementation. From a strict OO point of view, one could never inherit from a Singleton, so it really needs a different name.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号