对象克隆是制作对象副本的行为。作为Cody https://stackoverflow.com/questions/2144506/what-is-object-cloning-in-php/2144523#2144523指出,PHP 中的克隆是通过制作对象的浅拷贝来完成的。这意味着克隆对象的内部对象将not被克隆,除非您通过定义魔术方法明确指示对象也克隆这些内部对象__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;
例如,克隆的用例是您不希望外部对象扰乱对象的内部状态的情况。
假设您有一个带有内部对象地址的 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对象,User的内部Address将不会改变。如果您没有提供克隆,则外部对象would能够更改用户的内部地址,因为默认给出引用,而不是克隆。
希望这一切都有道理。
PS.:
但请注意,如果 Address 也有内部对象,则必须通过定义来确保 Address 在克隆时对其自身进行深层复制(按照本文的第二个示例)__clone()
在地址中。否则,你会因为试图找出数据被破坏的原因而感到头疼。