在大家写一个单例模式的代码时,很容易就会写出以下的代码
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
具体原理本人也不懂,希望懂的人可以留言解答以下,万分感谢