How to clone an array of objects in PHP?

PhpArraysObjectClone

Php Problem Overview


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?

Php Solutions


Solution 1 - Php

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

Solution 2 - Php

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

Solution 3 - Php

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

Solution 4 - Php

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

Solution 5 - Php

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.

Solution 6 - Php

A pure PHP 7.4 >= solution:

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

Solution 7 - 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.

Solution 8 - Php

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.

Solution 9 - Php

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.

Solution 10 - Php

or also

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

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

Solution 11 - Php

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.

Solution 12 - Php

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

Solution 13 - Php

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.

Solution 14 - Php

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

Solution 15 - Php

$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', )

Solution 16 - Php

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDisgruntledGoatView Question on Stackoverflow
Solution 1 - PhperaniView Answer on Stackoverflow
Solution 2 - PhpBoltClockView Answer on Stackoverflow
Solution 3 - PhpDaniel TeichmanView Answer on Stackoverflow
Solution 4 - PhpSébastien FauvelView Answer on Stackoverflow
Solution 5 - PhphakreView Answer on Stackoverflow
Solution 6 - PhpcelsowmView Answer on Stackoverflow
Solution 7 - PhpAndreKRView Answer on Stackoverflow
Solution 8 - PhpnuKsView Answer on Stackoverflow
Solution 9 - PhpTrendfischerView Answer on Stackoverflow
Solution 10 - PhpDaniele CrucianiView Answer on Stackoverflow
Solution 11 - PhpjgmjgmView Answer on Stackoverflow
Solution 12 - PhpSamer Abu GahgahView Answer on Stackoverflow
Solution 13 - PhpMinworkView Answer on Stackoverflow
Solution 14 - PhpDesolatorView Answer on Stackoverflow
Solution 15 - Phpuser12549678View Answer on Stackoverflow
Solution 16 - PhpPeymanView Answer on Stackoverflow