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 arrays are assigned by copy, while objects are assigned by reference. This means that:
$a = array();
$b = $a;
$b['foo'] = 42;
var_dump($a);
Will yield:
array(0) {
}
Whereas:
$a = new StdClass();
$b = $a;
$b->foo = 42;
var_dump($a);
Yields:
object(stdClass)#1 (1) {
["foo"]=>
int(42)
}
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.
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);
}
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.
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"}
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