在大家寫一個單例模式的代碼時,很容易就會寫出以下的代碼
class s
{
private static $single;
private function __construct()
{
}
public static function getSingle()
{
if(!self::$single){
self::$single = new self();
}
return self::$single;
}
//年長一點的同學還會寫出以下的魔術方法來阻止 深度複製 $s1 = clone $s2
private function __clone()
{
}
}
$s = s::getSingle();
這樣就足夠了,很明顯並不是,因爲我發現了以下兩種無解的破壞方式
首先派出的就是: 。。。 就決定是你了序列化 serialize和 unserialize
$s = s::getSingle();
$b1 = unserialize(serialize($s));
var_dump($s === $b1); //false
var_dump($b1 === s::getSingle()); //false
var_dump($s === s::getSingle()); //true
此時我們發現序列化出來的$b1並不是單例了,這個很多人估計工作中也會忘記吧,那我們就把 __sleep 和 __wakeup都設置爲私有,這樣就不會出現破壞單例吧,然而現實不允許呢,然後我發現了下面的測試,在我嘗試在類中加入了__wakeup方法
public function __wakeup()
{
self::$single = static::$single;
}
然後測試
$s = s::getSingle();
$b1 = unserialize(serialize($s));
var_dump($b1 === s::getSingle()); //false
var_dump($s === s::getSingle()); //true
看來反序列化的時候,靜態變量$single的值已經發生了改變,導致每次反序列化的時候就相當於新建了對象
猜測和我接下來說的第二種方式:反射有關,其中的newinstancewithoutconstructor更加無解,直接就不使用你的構造函數就可以實例化了
$r = new ReflectionClass('s');
$d1 = $r->newInstanceWithoutConstructor();
var_dump($s === $d1); //false
var_dump($d1 === s::getSingle()); //false
具體原理本人也不懂,希望懂的人可以留言解答以下,萬分感謝