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

发布于 2024-11-16 09:10:47 字数 140 浏览 3 评论 0原文

我有一系列对象。我知道对象是通过“引用”分配的,数组是通过“值”分配的。但是当我分配数组时,数组的每个元素都引用该对象,因此当我修改任一数组中的对象时,更改都会反映在另一个数组中。

有没有一种简单的方法来克隆数组,或者我必须循环遍历它来克隆每个对象?

I have an array of objects. I know that objects get assigned by "reference" and arrays by "value". But when I assign the array, each element of the array is referencing the object, so when I modify an object in either array the changes are reflected in the other.

Is there a simple way to clone an array, or must I loop through it to clone each object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

与酒说心事 2024-11-23 09:10:47
$array = array_merge(array(), $myArray);
$array = array_merge(array(), $myArray);
夏尔 2024-11-23 09:10:47

当您复制数组时,对相同对象的引用已经被复制。但听起来您想在创建第二个数组时浅复制深层复制第一个数组中引用的对象,因此您会得到两个不同但相似对象的数组。

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

$new = array();

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

References to the same objects already get copied when you copy the array. But it sounds like you want to shallow-copy deep-copy the objects being referenced in the first array when you create the second array, so you get two arrays of distinct but similar objects.

The most intuitive way I can come up with right now is a loop; there may be simpler or more elegant solutions out there:

$new = array();

foreach ($old as $k => $v) {
    $new[$k] = clone $v;
}
愿得七秒忆 2024-11-23 09:10:47

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

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

You need to clone objects to avoid having references to the same object.

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;
}
不离久伴 2024-11-23 09:10:47

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

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

As suggested by AndreKR, using array_map() is the best way to go if you already know that your array contains objects:

$clone = array_map(function ($object) { return clone $object; }, $array);
终止放荡 2024-11-23 09:10:47

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

使用序列化和反序列化进行数组克隆

If你的对象支持序列化,你甚至可以进行深浅复制/克隆,并浏览它们的睡眠状态并返回:

$f = new foo('moo');
$a = array($f);

$b = unserialize(serialize($a));

$b[0]->store='bar';
var_dump($a, $b);

但是,这可能有点冒险。

I opted for clone as well. Cloning an array does not work (you could consider some arrayaccess implementation to do so for you), so as for the array clone with 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);

Array clone with serialize and unserialize

If your objects support serialisation, you can even sort of deep shallow copy/clone with a tour into their sleeping state and back:

$f = new foo('moo');
$a = array($f);

$b = unserialize(serialize($a));

$b[0]->store='bar';
var_dump($a, $b);

However, that can be a bit adventurous.

感情旳空白 2024-11-23 09:10:47

纯 PHP 7.4 >= 解决方案:

$cloned = array_map(fn ($o) => clone $o, $original);

A pure PHP 7.4 >= solution:

$cloned = array_map(fn ($o) => clone $o, $original);
攒一口袋星星 2024-11-23 09:10:47

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

You need to loop it (possibly using a function like array_map() for that), there is no PHP function to automatically perform a deep copy of an array.

幸福还没到 2024-11-23 09:10:47

我是这样做的:

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 。

I've done it like this:

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

The function arg copies the array without cloning the objects,
then each nested object is cloned. So it won't work if the algorithm is not used inside a function.

Note this function clone the array recursively. You can use array_walk instead of array_walk_recursive if you do not want this to happen.

内心旳酸楚 2024-11-23 09:10:47

这是我对一系列对象和克隆的最佳实践。通常,为数组中使用的每个对象类(或接口)创建一个 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() 。因此,在重构代码时请注意这一点。

Here is my best practice on an array of objects and cloning. Usually it is a good idea, to have a Collection class for each class of objects (or interface), which are used in an array. With the magic function __clone cloning becomes a formalized routine:

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

To clone your array, use it as Collection and then clone it:

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

One step further, you should add a clone method to your class and each sub-class, too. This is important for deep cloning, or you might have unintended side effects:

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

An important note on using ArrayObject is, that you cannot use is_array() any longer. So be aware of this on refactoring your code.

轮廓§ 2024-11-23 09:10:47

或者也可以

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

,但价格昂贵,我更喜欢塞巴斯蒂安版本(array_map)

or also

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

but it is expensive, I prefer Sebastien version (array_map)

把时间冻结 2024-11-23 09:10:47

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

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

 $b = (array)$a;

对于深复制,我不推荐此解决方案:

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

这是为了深拷贝。它仅支持 PHP 类型的子集,并且会将对象交换为数组,或将数组交换为对象,这可能不是您想要的,并且可能会损坏二进制值等。

如果您为深层复制创建手动递归函数,则标量值和键的内存使用量将少得多,因此使用 json 或任何序列化程序都会对超出其执行点产生影响。

如果性能不是一个问题,它对对象等事物有更广泛的支持,那么使用 unserialize(serialize($a)) 进行深层复制可能会更好,尽管如果它因循环引用和其他一些不寻常的事情而中断,我不会感到惊讶。

array_merge_recursive 或 array_walk_recursive 也可用于数组。

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

Objects are passed by pointed by default and are not always easy to clone especially as they may have circular references. You would be better suited with a different choice of data structures.

For those providing solutions to shallow copy the easier way is this:

 $b = (array)$a;

For deep copies I do not recommend this solution:

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

This is for a deep copy. It only supports a subset of PHP types and will swap objects to array or arrays to objects which might not be what you want as well as potentially corrupting binary values and so on.

If you make a manual recursive function for deep copies the memory usage will be much less afterwards for scalar values and keys so using json or any serializer an impact beyond its point of execution.

It may be better to use unserialize(serialize($a)) for deep copies if performance is not a concern which has wider support for things such as objects though I would not be surprised if it breaks for circular references and several other unusual things.

array_merge_recursive or array_walk_recursive can also be used for arrays.

You can easily create your own recursive function that uses is_object and is_array to choose the appropriate means of copying.

手长情犹 2024-11-23 09:10:47

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

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

For PHP 5 and above one can use ArrayObject cunstructur to clone an array like the following:

$myArray = array(1, 2, 3);
$clonedArray = new ArrayObject($myArray);
草莓酥 2024-11-23 09:10:47

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

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

来自该库

If you have multidimensional array or array composed of both objects and other values you can use this method:

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

from that library.

俯瞰星空 2024-11-23 09:10:47

只需将此函数包含在您的所有类中即可。如果对象本身中有对象数组,这将对所有对象进行深度克隆。它将触发这些类中的所有 __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;
    }
}

Just include this function in all of your classes. This will do a deep clone of all objects in case if you have arrays of objects within the object itself. It will trigger all of the __clone() functions in these classes:

/**
 * 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;
    }
}
长伴 2024-11-23 09:10:47
$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', )
$a = ['a'=>'A','b'=>'B','c'=>'C'];
$b = $a+[];
$a['a'] = 'AA'; // modifying array $a
var_export($a);
var_export($b); 

Result:

array ( 'a' => 'AA', 'b' => 'B', 'c' => 'C', )
array ( 'a' => 'A', 'b' => 'B', 'c' => 'C', )
秋心╮凉 2024-11-23 09:10:47

我更喜欢递归方式:

function deepClone(mixed $object): mixed
{
    switch (gettype($object)) {
        case 'object':
            return clone $object;

        case 'array':
            $ret = [];
            foreach ($object as $key => $item) {
                $ret[$key] = deepClone($item);
            }
            return $ret;

        default:
            return $object;
    }
}

deepClone($array);

i prefer recursive way:

function deepClone(mixed $object): mixed
{
    switch (gettype($object)) {
        case 'object':
            return clone $object;

        case 'array':
            $ret = [];
            foreach ($object as $key => $item) {
                $ret[$key] = deepClone($item);
            }
            return $ret;

        default:
            return $object;
    }
}

deepClone($array);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文