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

我有一个对象的数组。 我知道对象是由“引用”和数组由“值”分配的。 但是,当我分配数组时,数组的每个元素都引用该对象,所以当我修改任一数组中的对象时,这些更改都会反映在另一个数组中。

有一个简单的方法来克隆一个数组,或者我必须通过循环克隆每个对象?

复制数组时,对相同对象的引用已经被复制。 但是当你创build第二个数组的时候,这听起来像是你想浅拷贝被第一个数组引用的对象的深度拷贝,所以你得到了两个不同但相似的对象数组。

我现在最直观的方法是循环; 那里可能有更简单或更优雅的解决scheme:

$new = array(); foreach ($old as $k => $v) { $new[$k] = clone $v; } 
 $array = array_merge(array(), $myArray); 

您需要克隆对象以避免引用相同的对象。

 function array_copy($arr) { $newArray = array(); foreach($arr as $key => $value) { if(is_array($value)) $newArray[$key] = array_copy($value); else if(is_object($value)) $newArray[$key] = clone $value; else $newArray[$key] = $value; } return $newArray; } 

正如AndreKR所build议的那样,如果您已经知道数组包含对象,那么使用array_map()是最好的方法:

 $clone = array_map(function ($object) { return clone $object; }, $array); 

我也select了克隆。 克隆一个数组是不行的(你可以考虑一些arrayaccess实现为你做),以便array_map数组克隆

 class foo { public $store; public function __construct($store) {$this->store=$store;} } $f = new foo('moo'); $a = array($f); $b = array_map(function($o) {return clone $o;}, $a); $b[0]->store='bar'; var_dump($a, $b); 

具有序列化和反序列化的数组克隆

如果你的对象支持序列化,你甚至可以将深度浅拷贝/克隆进入睡眠状态,然后返回:

 $f = new foo('moo'); $a = array($f); $b = unserialize(serialize($a)); $b[0]->store='bar'; var_dump($a, $b); 

但是,这可能有点冒险。

你需要循环它(可能使用像array_map()这样的函数),没有PHP函数自动执行数组的深层副本。

我已经这样做了:

 function array_clone($array) { array_walk_recursive($array, function(&$value) { if(is_object($value)) { $value = clone $value; } }); return $array; } 

函数arg拷贝数组而不克隆对象,然后克隆每个嵌套对象。 所以如果algorithm不在函数内部使用,它将不起作用。

注意这个函数recursion地克隆数组。 如果你不希望发生这种情况,你可以使用array_walk而不是array_walk_recursive

或者也是

 $nuarr = json_decode(json_encode($array)); 

但价格昂贵,我更喜欢Sebastien版本(array_map)

对象通过默认指针传递,并不总是很容易克隆,尤其是因为它们可能有循环引用。 你会更适合于不同的数据结构select。

对于那些提供浅拷贝解决scheme的更简单的方法是这样的:

  $b = (array)$a; 

对于深拷贝,我不build议这个解决scheme:

$ nuarr = json_decode(json_encode($ array));

这是一个深层复制。 它只支持PHPtypes的一个子集,并将对象交换到数组或数组中,这些对象可能不是您想要的,也可能会破坏二进制值等等。

如果你为深拷贝做一个手动的recursion函数,那么标量值和关键字的内存使用量就会less得多,所以使用json或者任何序列化器的影响超出了它的执行点。

如果性能不是更广泛地支持诸如对象之类的事情,那么使用反序列化(serialize($ a))可能会更好,但是如果它打破循环引用和其他一些不寻常的事情,我不会感到惊讶。

array_merge_recursive或array_walk_recursive也可以用于数组。

您可以轻松创build自己的recursion函数,使用is_object和is_array来select适当的复制方法。

这是我在对象和克隆arrays上的最佳做法。 通常,对于在数组中使用的每个对象(或接口)类都有一个Collection类是一个好主意。 随着__clone的魔术function成为一个forms化的例程:

 class Collection extends ArrayObject { public function __clone() { foreach ($this as $key => $property) { $this[$key] = clone $property; } } } 

要克隆你的数组,把它作为Collection使用,然后克隆它:

 $arrayObject = new Collection($myArray); $clonedArrayObject = clone $arrayObject; 

更进一步,您应该为您的类和每个子类添加一个克隆方法。 这对深度克隆很重要,否则可能会产生意想不到的副作用:

 class MyClass { public function __clone() { $this->propertyContainingObject = clone $this->propertyContainingObject; } } 

关于使用ArrayObject的一个重要的注意事项是,你不能再使用is_array() 。 所以要重构你的代码。

这个例子对我来说也是类似的情况:

 $new_array = (array) clone (object)$old_array;