Creating a Singleton base class in PHP 5.3
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
isSingleton
and
SingletonB
isSingleton
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.
精彩评论