咱们曾经在 PHP 设计模式之原型模式中探讨过对于 PHP 中对象复制的问题,这次就当做是一次温习。
原型模式能够看作是对象复制中的一个重要内容。在学习原型模式时,咱们理解到对象中的援用变量,也就是变量也是一个对象时,间接复制这个对象会导致其中的援用变量还是指向同一个对象。是不是有点绕,咱们还是用例子来阐明:
// clone 办法
class testA{public $testValue;}
class A
{
public static $reference = 0;
public $instanceReference = 0;
public $t;
public function __construct()
{
$this->instanceReference = ++self::$reference;
$this->t = new testA();}
public function __clone()
{
$this->instanceReference = ++self::$reference;
$this->t = new testA();}
}
$a1 = new A();
$a2 = new A();
$a11 = clone $a1;
$a22 = $a2;
var_dump($a11); // $instanceReference, 3
var_dump($a22); // $instanceReference, 2
$a1->t->testValue = '当初是 a1';
echo $a11->t->testValue, PHP_EOL; // ''$a2->t->testValue =' 当初是 a2';
echo $a22->t->testValue, PHP_EOL; // 当初是 a2
$a22->t->testValue = '当初是 a22';
echo $a2->t->testValue, PHP_EOL; // 当初是 a22
// 应用 clone 后
$a22 = clone $a2;
var_dump($a22); // $instanceReference, 4
$a2->t->testValue = '当初是 a2';
echo $a22->t->testValue, PHP_EOL; // NULL
$a22->t->testValue = '当初是 a22';
echo $a2->t->testValue, PHP_EOL; // 当初是 a2
首先,通过变量的变动,咱们能够看出应用 clone 关键字的对象复制会调用__clone()办法。这个魔术办法正在原型模式的外围所在。在这个办法中,咱们能够从新实例化或者定义对象中的援用成员。通过 clone,咱们让 $t 变量从新实例化,从而让 $t 成为了新的对象,从而防止援用带来的问题。
在对象的复制中,咱们须要特地留神的递归援用的问题。也就是对象外部援用了本身,将会导致来回的反复援用造成递归死循环。
// 循环援用问题
class B
{
public $that;
function __clone()
{
// Segmentation fault: 11
$this->that = clone $this->that;
// $this->that = unserialize(serialize($this->that));
// object(B)#6 (1) {// ["that"]=>
// object(B)#7 (1) {// ["that"]=>
// object(B)#8 (1) {// ["that"]=>
// *RECURSION* 有限递归
// }
// }
// }
}
}
$b1 = new B();
$b2 = new B();
$b1->that = $b2;
$b2->that = $b1;
$b3 = clone $b1;
var_dump($b3);
B 类中的 that 指向本身的实例,两个对象互相指向后再进行复制,就会呈现这种死循环的状况。应用序列化和反序列化输入后,咱们会看到 RECURSION 的援用提醒。这就是造成了递归的死循环。这种状况肯定要竭力防止。
上述例子中,咱们应用了序列化和反序列化这一招来解决援用问题。对象复制的对象变量来说(对象变量外面还有更多层次的援用变量),这种形式可能一次性地在最顶层的对象__clone()办法中解决援用问题。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202001/source/%E5%85%B3%E4%BA%8EPHP%E4%B8%AD%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E7%9A%84%E9%82%A3%E7%82%B9%E4%BA%8B%E5%84%BF.php
参考文档:
https://www.php.net/manual/zh/language.oop5.cloning.php
===========
各自媒体平台均可搜寻【硬核项目经理】