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共用一个遥控器,这显然是不合常理的。
