clone操作的致命缺陷
clone真的能够达到理想的复制效果吗?在某些情况下,你应该会发现,clone操作并没有我们想象中的那么完美。我们将以上的电视机类修改一下,然后做测试。
每台电视机都会附带一个遥控器,所以我们将会有一个遥控器类,遥控器和电视机是一种“聚合”关系(相对与“组合”关系,是一种较弱的依赖关系,因为一般情况电视机就算没有遥控也能正常使用),现在我们的电视机对象应该都持有一个到遥控器对象的引用。下面看看代码
PHP代码
/** 电视机类 */ class Television { /** 电视机编号 */ protected $_identity = 0; /** 屏幕高度 */ protected $_screenLength = 300; /** 屏幕宽度 */ protected $_screenHight = 200; /** 电视机外观颜色 */ protected $_color = 'black'; /** 遥控器对象 */ protected $_control = null; /** 构造函数中加载遥控器对象 */ public function __construct() { $this->setControl(new Telecontrol()); } /** 设置遥控器对象 */ public function setControl(Telecontrol $control) { $this->_control = $control; return $this; } /** 返回遥控器对象 */ public function getControl() { return $this->_control; } /** 返回电视外观颜色 */ public function getColor() { return $this->_color; } /** 设置电视机外观颜色 */ public function setColor($color) { $this->_color = (string)$color; return $this; } /** 返回电视机编号 */ public function getIdentity() { return $this->_identity; } /** 设置电视机编号 */ public function setIdentity($id) { $this->_identity = (int)$id; return $this; } public function __clone() { $this->setIdentity(0); } } /** 遥控器类 */ class Telecontrol { }
下面复制这样的一个电视机对象并且观察电视机的遥控器对象。
PHP代码
$tv1 = new Television(); $tv2 = clone $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 为 #3 echo '<br>'; echo $contr2; //contr2的object id 为#2
经过复制之后,我们查看对象id,通过clone操作从tv1复制出了tv2,tv1和tv2的对象id分别是 1和3,这表示tv1和tv2是引用两个不同的电视机对象,这符合clone操作的结果。然后我们分别获取了tv1的遥控器对象contr1和tv2的遥控器对象contr2,通过查看它们的对象 id我们发现contr1和contr2的对象id都是2,这表明它们是到同一个对象的引用,也就是说我们虽然从tv1复制出tv2,但是遥控器并没有被复制,每台电视机都应该配有一个遥控器,而这里tv2和tv1共用一个遥控器,这显然是不合常理的。