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

时间:2011-06-20 23:59:57

标签: php arrays object clone

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

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

15 个答案:

答案 0 :(得分:64)

$array = array_merge(array(), $myArray);

答案 1 :(得分:44)

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

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

$new = array();

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

答案 2 :(得分:18)

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

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;
}

答案 3 :(得分:13)

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

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

答案 4 :(得分:5)

我也选择了克隆。克隆数组不起作用(你可以考虑一些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);

然而,这可能有点冒险。

答案 5 :(得分:2)

你需要循环它(可能使用类似array_map()的函数),没有PHP函数来自动执行数组的深层复制。

答案 6 :(得分:2)

我这样做了:

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

函数arg复制数组而不克隆对象, 然后克隆每个嵌套对象。因此,如果算法未在函数内使用,它将无法工作。

注意此函数以递归方式克隆数组。如果您不希望发生这种情况,可以使用array_walk代替array_walk_recursive

答案 7 :(得分:2)

这是我对一系列对象和克隆的最佳实践。通常,对于在数组中使用的每个对象(或接口)类都有一个Collection类是个好主意。使用魔术函数__clone克隆成为一个正式的例程:

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()了。因此,请在重构代码时注意这一点。

答案 8 :(得分:2)

纯PHP 7.4> =解决方案:

fullName

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

对象在默认情况下通过指向传递,并不总是很容易克隆,尤其是因为它们可能具有循环引用。您可能更适合使用不同的数据结构选择。

对于那些提供浅拷贝解决方案的人来说,更简单的方法是:

 $b = (array)$a;

对于深层拷贝,我不建议使用此解决方案:

  

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

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

如果为深拷贝创建手动递归函数,那么标量值和键之后的内存使用量会更少,因此使用json或任何序列化程序会产生超出其执行点的影响。

如果性能不是一个对对象之类的东西有更广泛支持的问题,那么对深度拷贝使用unserialize(序列化($ a))可能会更好,尽管如果它打破循环引用和其他几个我不会感到惊讶不寻常的事情。

array_merge_recursive或array_walk_recursive也可用于数组。

您可以轻松创建自己的递归函数,该函数使用is_object和is_array来选择适当的复制方法。

答案 11 :(得分:0)

对于PHP 5及以上版本,可以使用ArrayObject cunstructur来克隆数组,如下所示:

$myArray = array(1, 2, 3);
$clonedArray = new ArrayObject($myArray);

答案 12 :(得分:0)

如果您具有多维数组或由对象和其他值组成的数组,则可以使用以下方法:

$cloned = Arr::clone($array);

来自that library

答案 13 :(得分:0)

只需在所有类中都包含此功能。如果对象本身中有对象数组,则这将对所有对象进行深度克隆。它将触发这些类中的所有__clone()函数:

/**
 * Clone the object and its properties
 */
public function __clone()
{
    foreach ($this as $key => $property)
    {
        if(is_array($property))
        {
            foreach ($property as $i => $o)
            {
                if(is_object($o)) $this->$key[$i] = clone $o;
                else $this->$key[$i] = $o;
            }
        }
        else if(is_object($property)) $this->$key = clone $property;
        else $this->$key = $property;
    }
}

答案 14 :(得分:-1)

$a = ['a'=>'A','b'=>'B','c'=>'C'];
$b = $a+[];
$a['a'] = 'AA'; // modifying array $a
var_export($a);
var_export($b); 

结果:

array ( 'a' => 'AA', 'b' => 'B', 'c' => 'C', )
array ( 'a' => 'A', 'b' => 'B', 'c' => 'C', )