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

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