Is there a function to make a copy of a PHP array to another?
I have been burned a few times trying to copy PHP arrays. I want to copy an array defined inside an object to a global outside it.
Is there a function to make a copy of a PHP array to another?
I have been burned a few times trying to copy PHP arrays. I want to copy an array defined inside an object to a global outside it.
In PHP, all variables except objects are assigned by the mechanism called copy-on-write, while objects are assigned by reference. Which means that for the arrays with scalar values simply $b = $a
already will give you a copy:
$a = array();
$b = $a;
$b['foo'] = 42;
var_dump($a);
Will yield:
array(0) {
}
Whereas with objects,
$a = new StdClass();
$b = $a;
$b->foo = 42;
var_dump($a);
Yields:
object(stdClass)#1 (1) {
["foo"]=>
int(42)
}
An edge case when array elements could be objects that need to be cloned as well, is explained in another answer
You could get confused by intricacies such as ArrayObject
, which is an object that acts exactly like an array. Being an object however, it has reference semantics.
Edit: @AndrewLarsson raises a point in the comments below. PHP has a special feature called "references". They are somewhat similar to pointers in languages like C/C++, but not quite the same. If your array contains references, then while the array itself is passed by copy, the references will still resolve to the original target. That's of course usually the desired behaviour, but I thought it was worth mentioning.
$copy = $original;
. Which doesn't work if the array elements are references. –
Trouble php
presents us with the least expected result, because this solution does not always work. $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
prints array0
while $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
prints array1
. Apparently some arrays are copied by reference. –
Jubilation next()
and similar functions. Perhaps now you see why I had to make my own answer to this question (and you are correct, it was sort of a special case, but I see it having use to many others coming here). –
Stickler foreach
or for
. Except for micro optimisations, I can't think of a use case where it would be better to use the next
, current
etc. constructs? –
Minelayer next()
function either, but I often need to use a while(list($key, $value) = each($array))
approach to iterate over an array, which does move the internal array pointer after each iteration (and you have to manually reset()
before you start and when you're done). My answer is due to me needing to clone the array I was currently iterating over, so I needed to make sure I didn't touch the internal array pointer (because foreach
moves the internal pointer, I couldn't use that to clone it). Maybe I'm not making sense, but hopefully you see why I did what I did. –
Stickler $a_copy = $a;
". Until then, @Reinis I.'s answer gets my upvote. –
Cliffcliffes $a=[foo=>bar];$b=$a;$b[foo]=42;echo$a[foo];
will print bar
; but $a=[foo=>bar];$b=$a;$b->foo=42;echo$a[foo];
will print 42
. I.e.: assigning an array variable to another variable will not create a copy instantly (for performance reasons); only if you modify the values - but not if you use the object syntax. –
Euhemerize PHP will copy the array by default. References in PHP have to be explicit.
$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a
$a = array(array('a', 'b'), 2, 3); $b = $a; $b[0][1] = 'c'; var_dump($a);
and $a doesn't change –
Porbeagle If you have an array that contains objects, you need to make a copy of that array without touching its internal pointer, and you need all the objects to be cloned (so that you're not modifying the originals when you make changes to the copied array), use this.
The trick to not touching the array's internal pointer is to make sure you're working with a copy of the array, and not the original array (or a reference to it), so using a function parameter will get the job done (thus, this is a function that takes in an array).
Note that you will still need to implement __clone() on your objects if you'd like their properties to also be cloned.
This function works for any type of array (including mixed type).
function array_clone($array) {
return array_map(function($element) {
return ((is_array($element))
? array_clone($element)
: ((is_object($element))
? clone $element
: $element
)
);
}, $array);
}
__clone()
function on your objects. See the PHP documentation on cloning for more information on that. The big reason why my array_clone
function doesn't do it for you is one of the same reasons PHP doesn't do it for you: because there is no efficient, effective, feasible way to protect against circular references. –
Stickler __clone()
function (because only the developer knows what needs to be cloned). If A
stores B
, you need to implement the __clone()
function on A
. And inside of A
's __clone()
function, you will need to make sure that you clone B
. Here's an example that shows how and why: sandbox.onlinephpfunctions.com/code/… –
Stickler C
inside B
, object D
inside C
, etc. This means I have to implement __clone()
for all objects stored on ABC
level. Furthermore since those objects are of vendor classes I have to override them all and instantiate with this extended classes to implement correct clone behavior. That's practically impossible in real application. –
Smew ReflectionClass
to get all properties of each object and clone them as well. I'm not going to stop you from doing that, but I would caution that there is probably a better way to solve your problem if you're having to clone objects that deep. Without knowing much about your situation, perhaps a dependency injection container would be something to look into. Just giving you some ideas to run with. –
Stickler __FUNCTION__
when used in a anonymous function. I'll update my answer to just use normal recursion. –
Stickler __FUNCTION__
in a variable on the first line of array_clone
, so you don't have to remember to update the name of the function in two places if you're planning on putting it somewhere more long-lived. See my edits for an example on how you would do that. –
Stickler max_depth
, to avoid accidental infinite recursions, or recursions that clone very large networks of objects. At each recursion, decrement max_depth. function array_clone($array, $max_depth) ... ? $max_depth <= 1 ? $element : array_clone($element, $max_depth-1) ...
Also, an "industrial strength" implementation would detect recursion, and correctly convert a recursive reference to a reference to the clone. Deep copy should be considered a rare, specialized, and potentially dangerous operation. –
Sultry Ctrl+C
on a StackOverflow answer than it is to redesign your app to avoid such a need (which is why I had to come up with this answer in the first place - I knew that adding a deep clone to my problem was much much cheaper than refactoring). –
Stickler When you do
$array_x = $array_y;
PHP copies the array, so I'm not sure how you would have gotten burned. For your case,
global $foo;
$foo = $obj->bar;
should work fine.
In order to get burned, I would think you'd either have to have been using references or expecting objects inside the arrays to be cloned.
simple and makes deep copy breaking all links
$new=unserialize(serialize($old));
I like array_replace
(or array_replace_recursive
).
$cloned = array_replace([], $YOUR_ARRAY);
It works like Object.assign
from JavaScript.
$original = [ 'foo' => 'bar', 'fiz' => 'baz' ];
$cloned = array_replace([], $original);
$clonedWithReassignment = array_replace([], $original, ['foo' => 'changed']);
$clonedWithNewValues = array_replace([], $original, ['add' => 'new']);
$original['new'] = 'val';
will result in
// original:
{"foo":"bar","fiz":"baz","new":"val"}
// cloned:
{"foo":"bar","fiz":"baz"}
// cloned with reassignment:
{"foo":"changed","fiz":"baz"}
// cloned with new values:
{"foo":"bar","fiz":"baz","add":"new"}
array_slice($arr, 0)
or when you don't care about keys, array_values($arr)
? I'm thinking they might be faster than searching in an array. Also, in javascript, it's quite popular to use Array.slice()
to clone arrays. –
Cush array_slice
and all the other methods mentioned here work very well. But if you want to merge several key-value-pairs (as it is also possible with JS-Objects via Object.assign
or the spread-syntax), array_replace
can be more useful. –
Algorism array_values()
which worked perfectly for my use-case. –
Callboard array_merge()
is a function in which you can copy one array to another in PHP.
$a_c = array_combine(array_keys($a), array_values($a))
. –
Superficial If you have only basic types in your array you can do this:
$copy = json_decode( json_encode($array), true);
You won't need to update the references manually
I know it won't work for everyone, but it worked for me
I know this as long time ago, but this worked for me..
$copied_array = array_slice($original_array,0,count($original_array));
$copied_array = array_slice($original_array, 0);
is sufficient. –
Sultry Safest and cheapest way I found is:
<?php
$b = array_values($a);
This has also the benefit to reindex the array.
This will not work as expected on associative array (hash), but neither most of previous answer.
Since this wasn't covered in any of the answers and is now available in PHP 5.3 (assumed Original Post was using 5.2).
In order to maintain an array structure and change its values I prefer to use array_replace
or array_replace_recursive
depending on my use case.
http://php.net/manual/en/function.array-replace.php
Here is an example using array_replace
and array_replace_recursive
demonstrating it being able to maintain the indexed order and capable of removing a reference.
The code below is written using the short array syntax available since PHP 5.4 which replaces array()
with []
.
http://php.net/manual/en/language.types.array.php
Works on either offset indexed and name indexed arrays
$o1 = new stdClass;
$a = 'd';
//This is the base array or the initial structure
$o1->ar1 = ['a', 'b', ['ca', 'cb']];
$o1->ar1[3] = & $a; //set 3rd offset to reference $a
//direct copy (not passed by reference)
$o1->ar2 = $o1->ar1; //alternatively array_replace($o1->ar1, []);
$o1->ar1[0] = 'z'; //set offset 0 of ar1 = z do not change ar2
$o1->ar1[3] = 'e'; //$a = e (changes value of 3rd offset to e in ar1 and ar2)
//copy and remove reference to 3rd offset of ar1 and change 2nd offset to a new array
$o1->ar3 = array_replace($o1->ar1, [2 => ['aa'], 3 => 'd']);
//maintain original array of the 2nd offset in ar1 and change the value at offset 0
//also remove reference of the 2nd offset
//note: offset 3 and 2 are transposed
$o1->ar4 = array_replace_recursive($o1->ar1, [3 => 'f', 2 => ['bb']]);
var_dump($o1);
Output:
["ar1"]=>
array(4) {
[0]=>
string(1) "z"
[1]=>
string(1) "b"
[2]=>
array(2) {
[0]=>
string(2) "ca"
[1]=>
string(2) "cb"
}
[3]=>
&string(1) "e"
}
["ar2"]=>
array(4) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
array(2) {
[0]=>
string(2) "ca"
[1]=>
string(2) "cb"
}
[3]=>
&string(1) "e"
}
["ar3"]=>
array(4) {
[0]=>
string(1) "z"
[1]=>
string(1) "b"
[2]=>
array(1) {
[0]=>
string(2) "aa"
}
[3]=>
string(1) "d"
}
["ar4"]=>
array(4) {
[0]=>
string(1) "z"
[1]=>
string(1) "b"
[2]=>
array(2) {
[0]=>
string(2) "bb"
[1]=>
string(2) "cb"
}
[3]=>
string(1) "f"
}
Creates a copy of the ArrayObject
<?php
// Array of available fruits
$fruits = array("lemons" => 1, "oranges" => 4, "bananas" => 5, "apples" => 10);
$fruitsArrayObject = new ArrayObject($fruits);
$fruitsArrayObject['pears'] = 4;
// create a copy of the array
$copy = $fruitsArrayObject->getArrayCopy();
print_r($copy);
?>
from https://www.php.net/manual/en/arrayobject.getarraycopy.php
This is the way I am copying my arrays in Php:
function equal_array($arr){
$ArrayObject = new ArrayObject($arr);
return $ArrayObject->getArrayCopy();
}
$test = array("aa","bb",3);
$test2 = equal_array($test);
print_r($test2);
This outputs:
Array
(
[0] => aa
[1] => bb
[2] => 3
)
$test2 = $test;
? What problem is ArrayObject
solving here? –
Khano <?php
function arrayCopy( array $array ) {
$result = array();
foreach( $array as $key => $val ) {
if( is_array( $val ) ) {
$result[$key] = arrayCopy( $val );
} elseif ( is_object( $val ) ) {
$result[$key] = clone $val;
} else {
$result[$key] = $val;
}
}
return $result;
}
?>
$arr_one_copy = array_combine(array_keys($arr_one), $arr_one);
Just to post one more solution ;)
private function cloneObject($mixed)
{
switch (true) {
case is_object($mixed):
return clone $mixed;
case is_array($mixed):
return array_map(array($this, __FUNCTION__), $mixed);
default:
return $mixed;
}
}
foreach($a as $key => $val) $b[$key] = $val ;
Preserves both key and values. Array 'a' is an exact copy of array 'b'
Define this:
$copy = create_function('$a', 'return $a;');
Copy $_ARRAY to $_ARRAY2 :
$_ARRAY2 = array_map($copy, $_ARRAY);
In php array, you need to just assign them to other variable to get copy of that array. But first you need to make sure about it's type, whether it is array or arrayObject or stdObject.
For Simple php array :
$a = array(
'data' => 10
);
$b = $a;
var_dump($b);
output:
array:1 [
"data" => 10
]
© 2022 - 2024 — McMap. All rights reserved.