什么是 php 中的对象克隆?

Posted

技术标签:

【中文标题】什么是 php 中的对象克隆?【英文标题】:what is Object Cloning in php? 【发布时间】:2011-01-09 19:29:48 【问题描述】:

谁能解释一下

什么时候应该在php中使用clone关键字?

【问题讨论】:

【参考方案1】:

对象克隆,就 PHP 5 而言,就是所谓的"shallow copy"。然后它在被克隆的对象上调用 __clone() 方法。

【讨论】:

【参考方案2】:

克隆用于创建对象的真实副本。将对象分配给另一个变量不会创建副本 - 相反,它会创建对与对象相同的内存位置的引用:

<?php

$o= new stdclass;
$o->a= 'b';
$o->b= 'c';

$o2= $o;
$o2->a= 'd';

var_dump($o);
var_dump($o2);

$o3= clone $o;
$o3->a= 'e';
var_dump($o);
var_dump($o3);

?>

此示例代码将输出以下内容:

object(stdClass)#1 (2) 
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"

object(stdClass)#1 (2) 
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"

object(stdClass)#1 (2) 
  ["a"]=>
  string(1) "d"
  ["b"]=>
  string(1) "c"

object(stdClass)#2 (2) 
  ["a"]=>
  string(1) "e"
  ["b"]=>
  string(1) "c"

【讨论】:

但是为什么要克隆它而不是做$o2= new stdClass; 修改像$o2-&gt;a= 'd'; 这样的属性会得到相同的结果,对吧? @samayo:不,$o3-&gt;b = $o-&gt;b 也是如此。请记住,leepowers 写了一个简单的示例,但是在更复杂的场景中,拥有复制所有属性的相同类型的对象(之后可以重新分配而无需修改原始对象)的好处是巨大的。【参考方案3】:

对象克隆是复制对象的行为。正如Cody 所指出的,PHP 中的克隆是通过制作对象的浅拷贝来完成的。这意味着克隆对象的内部对象将不会被克隆,除非您通过定义魔术方法 __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 对象的副本。上面的例子说明了这一点。 getAddress 方法将地址对象的克隆返回给调用对象。这意味着如果调用对象改变了地址对象,用户的内部地址不会改变。如果您没有提供克隆,那么外部对象能够更改用户的内部地址,因为默认情况下给出的是引用,而不是克隆。

希望这一切都有意义。

PS: 但是请注意,如果 Address 也有内部对象,则必须通过在 Address 中定义 __clone() 来确保 Address 在克隆时对其自身进行深层复制(根据我这篇文章的第二个示例)。否则你会为试图弄清楚为什么你的数据被搞砸而头疼。

【讨论】:

【参考方案4】:

如果您需要深度克隆 - 即子对象的克隆和孙对象的克隆 - 您可以覆盖每个类中的 __clone,或者简单地序列化+反序列化对象:

function deepClone($object)

    return unserialize(serialize($object));

【讨论】:

这是一个很好的解决方法。您为我节省了数小时的编码时间,谢谢!【参考方案5】:

正如其他答案中所解释的,clone 制作了对象的浅拷贝

如果您需要制作深拷贝(即递归拷贝),您可以重载__clone() 方法。

你也可以使用这个库:MyCLabs\DeepCopy,它比简单的克隆更简单更强大。

【讨论】:

以上是关于什么是 php 中的对象克隆?的主要内容,如果未能解决你的问题,请参考以下文章

PHP中的对象复制与克隆

如何在 PHP 中克隆对象数组?

php 克隆 __clone

php对象克隆

Java中的深克隆和浅克隆

克隆PHP对象并在克隆上设置protected属性