如何在 PHP 中克隆对象数组?
我有一系列对象。我知道对象是通过“引用”分配的,数组是通过“值”分配的。但是当我分配数组时,数组的每个元素都引用该对象,因此当我修改任一数组中的对象时,更改都会反映在另一个数组中。
有没有一种简单的方法来克隆数组,或者我必须循环遍历它来克隆每个对象?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
当您复制数组时,对相同对象的引用已经被复制。但听起来您想在创建第二个数组时
浅复制深层复制第一个数组中引用的对象,因此您会得到两个不同但相似对象的数组。我现在能想到的最直观的方法是循环;可能有更简单或更优雅的解决方案:
References to the same objects already get copied when you copy the array. But it sounds like you want to
shallow-copydeep-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:
您需要克隆对象以避免引用同一对象。
You need to clone objects to avoid having references to the same object.
正如 AndreKR 所建议的,如果您已经知道数组包含对象,那么使用 array_map() 是最好的方法:
As suggested by AndreKR, using array_map() is the best way to go if you already know that your array contains objects:
我也选择了克隆。克隆数组不起作用(您可以考虑使用一些 arrayaccess 实现来为您执行此操作),因此对于使用 array_map 进行数组克隆:
使用序列化和反序列化进行数组克隆
If你的对象支持序列化,你甚至可以进行深浅复制/克隆,并浏览它们的睡眠状态并返回:
但是,这可能有点冒险。
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:
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:
However, that can be a bit adventurous.
纯 PHP 7.4 >= 解决方案:
A pure PHP 7.4 >= solution:
您需要循环它(可能使用像 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.我是这样做的:
函数 arg 复制数组而不克隆对象,
然后每个嵌套对象都会被克隆。因此,如果该算法不在函数内部使用,它将无法工作。
请注意,此函数递归地克隆数组。如果您不希望发生这种情况,可以使用 array_walk 代替 array_walk_recursive 。
I've done it like this:
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 ofarray_walk_recursive
if you do not want this to happen.这是我对一系列对象和克隆的最佳实践。通常,为数组中使用的每个对象类(或接口)创建一个 Collection 类是一个好主意。使用神奇函数 __clone 克隆成为一种正式的例程:
要克隆数组,将其用作 Collection,然后克隆它:
更进一步,您应该向类和每个子类添加一个克隆方法, 也。这对于深度克隆很重要,否则可能会产生意想不到的副作用:
使用 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:To clone your array, use it as Collection and then clone it:
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:
An important note on using ArrayObject is, that you cannot use
is_array()
any longer. So be aware of this on refactoring your code.或者也可以
,但价格昂贵,我更喜欢塞巴斯蒂安版本(array_map)
or also
but it is expensive, I prefer Sebastien version (array_map)
默认情况下,对象是通过指针传递的,并且并不总是容易克隆,特别是因为它们可能具有循环引用。您会更适合选择不同的数据结构。
对于那些提供浅复制解决方案的人来说,更简单的方法是:
对于深复制,我不推荐此解决方案:
这是为了深拷贝。它仅支持 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:
For deep copies I do not recommend this solution:
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.
对于 PHP 5 及更高版本,可以使用 ArrayObject cunstructur 来克隆数组,如下所示:
For PHP 5 and above one can use
ArrayObject
cunstructur to clone an array like the following:如果您有多维数组或由对象和其他值组成的数组,您可以使用此方法:
来自该库。
If you have multidimensional array or array composed of both objects and other values you can use this method:
from that library.
只需将此函数包含在您的所有类中即可。如果对象本身中有对象数组,这将对所有对象进行深度克隆。它将触发这些类中的所有 __clone() 函数:
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:结果:
Result:
我更喜欢递归方式:
i prefer recursive way: