对象克隆是复制对象的行为。正如Cody所指出的那样,在PHP中进行克隆是通过对对象进行浅表复制来完成的。这意味着除非您通过定义magic方法明确指示对象也克隆这些内部对象,否则 克隆已克隆对象的内部对象__clone()
。
如果不使用该__clone
方法,则新对象的内部对象将是与克隆的原始对象的内部对象相同的对象在内存中的引用。
考虑以下示例:
// in this exampe the internal member $_internalObject of both objects
// reference the same instance of stdClass in memory.
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
}
$classA = new CloneableClass();
$classB = clone $classA;
// in this exampe the internal member $_internalObject of both objects
// DON'T reference the same instance of stdClass in memory, but are inividual instances
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
// on clone, make a deep copy of this object by cloning internal member;
public function __clone()
{
$this->_internalObject = clone $this->_internalObject;
}
}
$classA = new CloneableClass();
$classB = clone $classA;
例如,用于克隆的用例是您不希望外部对象与对象的内部状态发生混乱的情况。
假设您有一个带有内部对象Address的User类。
class Address
{
private $_street;
private $_streetIndex;
private $_city;
// etc...
public function __construct( $street, $streetIndex, $city /* etc.. */ )
{
/* assign to internal values */
}
}
class User
{
// will hold instance of Address
private $_address;
public function __construct()
{
$this->_address = new Address( 'somestreet', '1', 'somecity' /* etc */ );
}
public function getAddress()
{
return clone $this->_address;
}
}
出于参数考虑,假设您不希望外部对象与User对象的内部Address混淆,但您确实希望能够为它们提供Address对象的副本。上面的示例对此进行了说明。该getAddress
方法将地址对象的克隆返回给调用对象。这意味着,如果调用对象更改了地址对象,则用户的内部地址不会更改。如果您不提供克隆,则外部对象 能够更改用户的内部地址,因为默认情况下会提供引用,而不是克隆。
希望这一切都有意义。
请注意,如果Address也具有内部对象,则必须通过__clone()
在Address中进行定义来确保Address在克隆时复制其自身的深层副本(根据本帖子的第二个示例)。否则,您将很难尝试弄清楚数据为何被破坏。