【问题标题】:Object copy versus clone in PHPPHP中的对象复制与克隆
【发布时间】:2011-10-21 19:39:54
【问题描述】:

考虑以下几点:

$object1 = new stdClass();
$object2 = $object1;
$object3 = clone $object1;

$object1->content = 'Ciao';

var_dump($object1);
 // Outputs object(stdClass)#1 (1) { ["content"]=> string(4) "Ciao" }
var_dump($object2);
 // Outputs object(stdClass)#1 (1) { ["content"]=> string(4) "Ciao" }
var_dump($object3);
 // Outputs object(stdClass)#2 (0) { }

$object2 的内容与$object1 相同是正常的 PHP 行为吗?

在我看来,$object2 是对 $object1 的引用,而不是副本。 在更改内容之前克隆对象确实像副本一样。 这种行为与变量发生的行为不同,对我来说似乎不直观。

【问题讨论】:

  • 这只是由于缺少规范而导致的另一个 PHP-WTF。
  • 你能详细说明为什么这对你来说不直观吗?
  • 这对我来说很不直观,因为逻辑会随着变量的类型而变化。正如以下答案中所解释的,例如,它不会以数组的方式运行。
  • 在我看来,它相当不直观,因为$obj2 = $obj1$obj2 =& $obj1 做同样的事情。
  • @Antti29 - 他们做的事情并不完全相同。 $obj2 = $obj1 导致对同一底层对象的 2 个单独引用。因此,如果您随后执行$obj2 = $obj3,则您的$obj1 变量不受影响。但是,如果您从 $obj2 =& $obj1 开始,您最终会得到 2 个共享相同引用的变量!如果您然后执行$obj2 = $obj3,您会发现$obj1 现在也指向$obj3

标签: php object clone


【解决方案1】:

是的,这很正常。在 PHP5 中,对象总是通过引用“分配”。要实际复制一个对象,您需要clone它。

为了更正确,让我引用the manual

从 PHP5 开始,对象变量不再包含对象本身作为值。它只包含一个对象标识符,允许对象访问者找到实际对象。当一个对象通过参数发送、返回或分配给另一个变量时,不同的变量不是别名:它们持有标识符的副本,它指向同一个对象。

【讨论】:

    【解决方案2】:

    这很正常,我不会认为这是不直观的(对于对象实例):

    $object1 = new stdClass();
    

    $object1分配一个新的对象实例。

    $object2 = $object1;
    

    将对象实例分配给$object2

    $object3 = clone $object1;
    

    将从现有对象实例克隆的新对象实例分配给$object3

    如果不是这样,每次你需要传递一个具体的对象实例时,你都需要通过引用传递它。至少这很麻烦,但 PHP 在版本 4 中这样做了(比较 zend.ze1_compatibility_mode core )。那没用。

    Cloning allows the object to specify how it get's copied.

    【讨论】:

    • @stereofrog:从面向对象的角度来看,它不是。然而,PHP实际上 也制作了一个副本,即对象标识符的副本。自 PHP 5 起,对象值只能通过标识符获得,所以实际上,即使使用“我期望一个副本”,这也很直观:您将获得对象标识符的副本。然而,关键点可能是了解如何在 PHP 中实现 OO。
    • @stereofrog:当对象每次经过某个地方时都会克隆自己时,这会更加令人困惑。当一只狗穿过一扇门时,你也永远不会看到它分裂成两个相同的副本(其中一只狗总是呆在外面......)。另一方面,当我给某人我的电话号码(一个值/原始类型)并且他写下来时,他只有一个副本,而不是号码本身。将原始类型和对象的行为相互比较是没有用的。
    • @stereofrog:为什么? 是正确的问题。为了更好地说明原因,OP应该更多地分享对他来说不直观的东西。否则很难回答。其次,就语言而言,分配和复制(写入时)可能有所不同。这可能会让人了解语言的工作原理,并促进理解将语言用作工具,而不是对它寄予期望。
    【解决方案3】:

    对象复制与对象克隆

    class test{
    public $name;
    public $addr;
    }
    // i create a object $ob
    $ob=new test();
    
    // object copy 
    
    $ob2=$ob;
    
    // in object copy both object will represent same memory address 
    // example 
    $ob->name='pankaj raghuwanshi';
    
    // i am printing second object
    echo $ob2->name;
    // output is : pankaj raghuwanshi
    
    // another example 
    
    $ob2->name='raghuwanshi pankaj';
    echo $ob->name;
    // output is :  raghuwanshi pankaj
    
    // it means in copy of object original and copy object share same memory place
    

    现在克隆一个对象

    $ob1=clone $ob;
    
    echo $ob1->name;  // output is :  raghuwanshi pankaj
    echo $ob->name;   // output is :  raghuwanshi pankaj
    
     $ob1->name='PHP Clone';
     $ob->name='PHP Obj';
    
    echo $ob1->name;  // output is :  PHP Clone
    echo $ob->name;   // output is :  PHP Obj
    
    // on the base of these output we can say both object have their own memory space 
    // both are independent 
    

    【讨论】:

    • 这个答案是正确的例子
    【解决方案4】:

    php5 中的对象本质上是指针,即一个对象变量只包含位于其他地方的对象数据的地址。分配$obj1 = $obj2 仅复制此地址,不会触及数据本身。这可能看起来确实违反直觉,但实际上它非常实用,因为您很少需要对象的两个副本。我希望 php 数组使用相同的语义。

    【讨论】:

    • 有些函数当然只接受原生数组。 $result = new ArrayObject(array_map($cb, $arrOb->getArrayCopy()));
    猜你喜欢
    • 2013-04-06
    • 2013-05-29
    • 2011-10-17
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 2019-11-18
    • 2011-04-15
    相关资源
    最近更新 更多