- URL: https://www.laruence.com/en/2011/03/18/1909.html
- Please include attribution when republishing.
We often define a Singleton this way:
class Singleton {
private static $instance = NULL;
/** do not allow direct constructor calls */
private function __construct() {
}
/** do not allow deep copy */
private function __clone() {
}
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Many people remember to protect against deep copy, but actually we overlook one point:
<?php $a = Singleton::getInstance(); $b = unserialize(serialize($a)); var_dump($a === $b); //bool(false)
Haha, so we still need to patch it up — add protection against serialization:
class Singleton {
private static $instance = NULL;
/** do not allow direct constructor calls */
private function __construct() {
}
/** do not allow deep copy */
private function __clone() {
}
/** do not allow serialize */
private function __sleep() {
}
/** do not allow unserialize */
private function __wakeup() {
}
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
However, sometimes we want our Singleton class to be serializable. In that case, consider the following approach:
class Singleton {
private static $instance = NULL;
/** do not allow direct constructor calls */
private function __construct() {
}
/** do not allow deep copy */
private function __clone() {
}
public function __wakeup() {
self::$instance = $this;
}
/** cleanup is needed when the singleton switches over */
public function __destruct() {
self::$instance = NULL;
}
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Note in the above: on wakeup we switch the current singleton instance, in order to guarantee the singleton at the moment of serialization/deserialization.
Also, for some Singleton classes that hold global resources, we need to define a destructor to reclaim resources during the switch.
Now, please look carefully, then think about whether this code has any problems.
Keep reading: under some conditions, this code may not achieve our goal, for example:
$a = Singleton::getInstance(); $a = unserialize(serialize($a)); var_dump($a === Singleton::getInstance()); //bool(false)
Everyone can think about why. If you don't want to think, check out my next article.
Finally, an ad,,, follow me on Sina Weibo: http://t.sina.com.cn/laruence, 🙂
Be First to Comment