如何在PHP中创建对象的副本?

如何在PHP中创建对象的副本?,php,copy,clone,shallow-copy,Php,Copy,Clone,Shallow Copy,在PHP中,对象似乎是通过引用传递的。即使是赋值操作符也似乎没有创建对象的副本 这里有一个简单的、人为的证明: <?php class A { public $b; } function set_b($obj) { $obj->b = "after"; } $a = new A(); $a->b = "before"; $c = $a; //i would especially expect this to create a copy. set_b($a);

在PHP中,对象似乎是通过引用传递的。即使是赋值操作符也似乎没有创建对象的副本

这里有一个简单的、人为的证明:

<?php

class A {
    public $b;
}


function set_b($obj) { $obj->b = "after"; }

$a = new A();
$a->b = "before";
$c = $a; //i would especially expect this to create a copy.

set_b($a);

print $a->b; //i would expect this to show 'before'
print $c->b; //i would ESPECIALLY expect this to show 'before'

?>

在这两种印刷品中,我都得到了“追求”

那么,如何通过值而不是引用将$a传递给set_b()


在PHP5+中,对象是通过引用传递的。在PHP4中,它们是按值传递的(这就是为什么它有运行时按引用传递,这已被弃用)

您可以使用PHP5中的“克隆”操作符复制对象:

$objectB = clone $objectA;

而且,只是通过引用传递对象,而不是像您在问题中所说的那样传递所有对象…

答案通常在Java书籍中找到

  • 克隆: 如果不重写克隆方法,则默认行为为浅复制。如果对象只有基元成员变量,则完全可以。但在一种以另一个对象作为成员变量的无类型语言中,这是一个令人头痛的问题

  • 序列化/反序列化

  • $new\u object=unserialize(序列化($your\u object))


    根据对象的复杂性,这将以高昂的成本实现深度复制。

    根据前面的评论,如果您有另一个对象作为成员变量,请执行以下操作:

    class MyClass {
      private $someObject;
    
      public function __construct() {
        $this->someObject = new SomeClass();
      }
    
      public function __clone() {
        $this->someObject = clone $this->someObject;
      }
    
    }
    
    现在您可以进行克隆:

    $bar = new MyClass();
    $foo = clone $bar;
    

    如果要在不同实例中完全复制对象的属性,可能需要使用以下技术:


    将其序列化为JSON,然后将其反序列化回Object。

    此代码有助于克隆方法

    class Foo{
    
        private $run=10;
        public $foo=array(2,array(2,8));
        public function hoo(){return 5;}
    
    
        public function __clone(){
    
            $this->boo=function(){$this->hoo();};
    
        }
    }
    $obj=new Foo;
    
    $news=  clone $obj;
    var_dump($news->hoo());
    

    我在做一些测试,结果是:
    class A {
      public $property;
    }
    
    function set_property($obj) {
      $obj->property = "after";
      var_dump($obj);
    }
    
    $a = new A();
    $a->property = "before";
    
    // Creates a new Object from $a. Like "new A();"
    $b = new $a;
    // Makes a Copy of var $a, not referenced.
    $c = clone $a;
    
    set_property($a);
    // object(A)#1 (1) { ["property"]=> string(5) "after" }
    
    var_dump($a); // Because function set_property get by reference
    // object(A)#1 (1) { ["property"]=> string(5) "after" }
    var_dump($b);
    // object(A)#2 (1) { ["property"]=> NULL }
    var_dump($c);
    // object(A)#3 (1) { ["property"]=> string(6) "before" }
    
    // Now creates a new obj A and passes to the function by clone (will copied)
    $d = new A();
    $d->property = "before";
    
    set_property(clone $d); // A new variable was created from $d, and not made a reference
    // object(A)#5 (1) { ["property"]=> string(5) "after" }
    
    var_dump($d);
    // object(A)#4 (1) { ["property"]=> string(6) "before" }
    
    ?>
    

    为了澄清PHP使用的是写时复制,所以在修改之前,基本上所有内容都是一个参考,但是对于对象,您需要使用克隆和_clone()魔术方法,就像在接受的答案中一样。

    在本例中,我们将创建iPhone类,并通过克隆

    class iPhone {
    
    public $name;
    public $email;
    
        public function __construct($n, $e) {
    
           $this->name = $n;
           $this->email = $e;
    
        }
    }
    
    
    $main = new iPhone('Dark', 'm@m.com');
    $copy = clone $main;
    
    
    // if you want to print both objects, just write this    
    
    echo "<pre>"; print_r($main);  echo "</pre>";
    echo "<pre>"; print_r($copy);  echo "</pre>";
    
    class-iPhone{
    公共名称;
    公费邮件;
    公共函数构造($n,$e){
    $this->name=$n;
    $this->email=$e;
    }
    }
    $main=新iPhone('Dark','m@m.com');
    $copy=clone$main;
    //如果要同时打印这两个对象,只需编写以下内容
    回声“;打印(主);回声“;
    回声“;打印(复印件);回声“;
    
    在极少数情况下,您实际上需要这种行为。因此,如果您发现自己经常使用它,那么您编写代码的方式可能有更根本的错误?不,还没有必要使用它。
    (object)((array)$objectA)
    可能会得到与使用
    克隆$objectA
    新stdClass
    相同的预期结果,并且性能更好“即使赋值运算符似乎也不会创建对象的副本。”-我希望不会!如果他们创建了,结果将不再是OO语言(出于所有实际目的).1在PHP中进行深度复制的好方法,也很简单。让我问你一些关于PHP clone关键字提供的标准浅层复制的问题,你说只有原始成员变量被复制:PHP数组/字符串被认为是原始成员变量,所以它们被复制了,对吗?对任何人来说:a“浅“复制(
    $a=clone$b
    ,没有魔法
    \uu clone()
    方法在起作用)相当于定期查看对象
    $b
    的每个属性,并使用
    =
    在同一类的新成员中分配给同一属性。作为对象的属性不会得到
    克隆
    d,数组中的对象也不会得到;通过引用绑定的变量也是如此;其他一切都只是val然后像任何赋值一样复制。完美!json_解码(json_编码($obj));不克隆私有/受保护属性和任何方法…取消序列化(也不序列化克隆方法…太棒了!我终于摆脱了PhpStorm的错误;
    从无效上下文调用方法u克隆
    :)这会增加很多运行时开销。您正在将对象序列化为字符串,然后将该字符串解析回新变量。虽然这是您想要做的,但它的速度非常慢。您不仅要使用时间和内存将所有对象转换成字符串并返回,而且还破坏了PHPs可能的CopyOnWrite机制ism。一个更好的方法是按照下面的建议正确实现您的
    \u clone
    方法。请参阅以获得深入的解释。只想向阅读本文的任何人添加,克隆将保留对原始对象的引用。因此,使用克隆对象运行MySQL查询可能会产生不可预测的结果,因为执行不是以线性的方式发生的。为了纠正一个常见的误解(我想连PHP文档都弄错了!),PHP5的对象不是“通过引用传递的”。就像在Java中一样,它们还有一个额外的间接层次——变量指向“对象指针”,它指向一个对象。因此,两个变量可以指向同一个对象,而不会引用同一个值。从这个例子可以看出:
    $a=newstdclass$b=&$a$a=42;var_出口(b美元)
    此处
    $b
    是对变量
    $a
    的引用;如果将
    =&
    替换为普通的
    =
    ,则它不是引用,仍然指向原始对象。运行时按引用传递是一个坏主意,因为它使函数调用的效果取决于函数的实现,而不是规范。这与默认值pass by value无关。@Alex您能详细说明一下您的评论吗?(无论是在这里还是在其他地方)你的观点在我看来有点不清楚。@Ælex-re“克隆将保留对原始对象的引用”——更准确地说,克隆是对对象属性的浅拷贝。如果对象包含其他对象,那么这些嵌套对象现在将有两个对它们的引用。有时候
    class iPhone {
    
    public $name;
    public $email;
    
        public function __construct($n, $e) {
    
           $this->name = $n;
           $this->email = $e;
    
        }
    }
    
    
    $main = new iPhone('Dark', 'm@m.com');
    $copy = clone $main;
    
    
    // if you want to print both objects, just write this    
    
    echo "<pre>"; print_r($main);  echo "</pre>";
    echo "<pre>"; print_r($copy);  echo "</pre>";