如何在PHP中创建对象的副本?
在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
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>";