php5对象复制、clone、浅复制与深复制实例详解(4)

由此可见,clone操作有这么一个非常大的缺陷:使用clone操作复制对象时,当被复制的对象有对其它对象的引用的时候,引用的对象将不会被复制。然而这种情况又非常的普遍,现今 “合成/聚合复用”多被提倡用来代替“继承复用”,“合成”和“聚合”就是让一个对象拥有对另一个对象的引用,从而复用被引用对象的方法。我们在使用 clone的时候应该考虑到这样的情况。那么在clone对象的时候我们应该如何去解决这样的一个缺陷呢?可能你很快就想到了之前提到的__clone魔术方法,这确实是一种解决方案。

方案1:用__clone魔术方法弥补

前面我们已经介绍了__clone魔术方法的用法,我们可以在__clone方法中将被复制对象中其它对象的引用重新引用到一个新的对象。下面我们看看修改后的__clone()魔术方法:

PHP代码

public function __clone()
{
  $this->setIdentity(0);
  //重新设置一个遥控器对象
  $this->setControl(new Telecontrol());
}

第04行中我们为复制出来的电视机对象重新设置了一个遥控器,我们按照之前的方法查看对象的id可以发现,两台电视机的遥控器拥有不同的对象id,这样我们的问题就解决了。

但是这样的方式大概并不算太好,如果被复制对象中有多个到其它对象的引用,我们必须在__clone方法中逐个的重新设置,更糟糕的是如果被复制对象的类由第三方提供,我们无法修改代码,那复制操作基本就无法顺利完成了。

我们使用clone来复制对象,这种复制叫做“浅复制”:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。也就是说,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。相对于“浅复制”,当然也有一个“深复制”:被复制的对象的所有的变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。也就是说,深复制把要复制的对象所引用的对象都复制了一遍。深复制需要决定深入到多少层,这是一个不容易确定的问题,此外可能会出现循环引用的问题,这些都必须小心处理。我们的方案2将是一个深复制的解决方案。

方案2:利用串行化做深复制

PHP有串行化(serialize)和反串行化(unserialize)函数,我们只需要用serialize()将一个对象写入一个流,然后从流中读回对象,那么对象就被复制了。在JAVA语言里面,这个过程叫做“冷藏”和“解冻”。下面我们将测试一下这个方法:

PHP代码

$tv1 = new Television();
$tv2 = unserialize(serialize($tv1));//序列化然后反序列化
$contr1 = $tv1->getControl(); //获取tv1的遥控器contr1
$contr2 = $tv2->getControl(); //获取tv2的遥控器contr2
echo $tv1;  //tv1的object id 为 #1
echo '<br>';
echo $contr1; //contr1的object id 为#2
echo '<br>';
echo $tv2;  //tv2的object id 为 #4
echo '<br>';
echo $contr2; //contr2的object id 为#5


      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4991.html