Validate PHP array and object passing by reference
Aug 25, 2020
PHP
What you did
Copying an array containing objects with foreach can be an unexpected bug. (there were) Sample code verifies what happens when you copy an array, a two-dimensional array, an object, or an object containing an object, and how it works as expected.
#Environment
- PHP7.4
Implementation
array
Since the array is passed by value, if you assign it to another variable, rewriting the value of another variable does not affect the original variable.
$test = ['a'=>1,'b'=>2];
$test2 = $test;
$test2['a'] = 3;
var_dump($test);
exit;
/*
array (size=2)
'a' => int 1 ← unchanged
'b' => int 2
*/
Two-dimensional array
Same as a normal array.
$test = ['a'=>['c'=>1],'b'=>['d'=>2]];
$test2 = $test;
$test2['a']['c'] = 3;
var_dump($test);
exit;
/*
array (size=2)
'a' =>
array (size=1)
'c' => int 1 ← unchanged
'b' =>
array (size=1)
'd' => int 2
*/
Object (simply assigned) ← Addictive point 1
Since the object is passed by reference (exactly the object ID? Manual), the value of another variable Any changes will also affect the original variables.
$test = (object)['a'=>1,'b'=>2];
$test2 = $test;
$test2->a = 3;
var_dump($test);
exit;
/*
object(stdClass)[161]
public'a' => int 3 ← changed
public'b' => int 2
*/
object (clone and assign)
If you want to handle it as another object, use clone
.
$test = (object)['a'=>1,'b'=>2];
$test2 = clone $test;
$test2->a = 3;
var_dump($test);
exit;
/*
object(stdClass)[161]
public'a' => int 1 ← unchanged
public'b' => int 2
*/
Object containing object (clone and assign) ← Addictive point 2
Even if cloned, the objects in the object will be passed by reference and retain the same reference (reference). (← see comment)
This is because PHP clone is a shallow copy. (Manuals)
$test = (object)['a'=>(object)['c'=>1],'b'=>(object)['d'=>2]];
$test2 = clone $test;
$test2->a->c = 3;
var_dump($test);
exit;
/*
object(stdClass)[210]
public'a' =>
object(stdClass)[161]
public'c' => int 3 ← changed
public'b' =>
object(stdClass)[171]
public'd' => int 2
*/
Object containing object (serialized & deserialized and assigned)
Manual describes to implement __clone
, but this is not always possible.
The easiest way is to serialize and then deserialize.
$test = (object)['a'=>(object)['c'=>1],'b'=>(object)['d'=>2]];
$test2 = unserialize(serialize($test));
$test2->a->c = 3;
var_dump($test);
exit;
/*
object(stdClass)[211]
public'a' =>
object(stdClass)[161]
public'c' => int 1 ← unchanged
public'b' =>
object(stdClass)[175]
public'd' => int 2
*/
#Reference Thank you very much. https://qiita.com/A-Kira/items/749de2c83dfd07feb3b3 https://qiita.com/horikeso/items/29c8d412e57f2097855b