Xriuk
Xriuk

Reputation: 487

PHP is accessing nested arrays copying them?

Let's say I have an array (it really could have any depth):

$arr = array(
  "lvl1" => array(
    "lvl2 => ...
  )
)

Now in a function I need to access it like this:

$path = array("lvl1", "lvl2", ...); // array of ordered indexes
$tmp = $arr;
foreach($path as $lvl){
  ...// other read-only/copy stuff happening on the array, no editing
  $tmp = $tmp[$lvl];
}

At this point, just out of curiosity (no real optimization here), am I making copies of copies everytime? Or is it just using references automatically?

Upvotes: 2

Views: 70

Answers (1)

sevavietl
sevavietl

Reputation: 3812

TL;DR If you are using PHP 7 the array won't be copied internally unless you change it. This is called copy-on-write.

To understand how PHP works under the hood you can read Reference Counting Basics:

A PHP variable is stored in a container called a "zval".

PHP is smart enough not to copy the actual variable container when it is not necessary.

Let's try to illustrate this on your simplified example using debug_zval_dump:

$array = [
        'lvl1' => [
                'lvl2' => [
                        'lvl3' => [
                        ],
                ],
        ],
];

$path = ['lvl1', 'lvl2', 'lvl3'];

$tmp = $array;

foreach ($path as $lvl) {
        debug_zval_dump($array);

        $tmp = $tmp[$lvl];
}

debug_zval_dump($array);

If you run this code you will get the following output:

array(1) refcount(4){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(2){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(2){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(2){
      }
    }
  }
}

Pay attention to refcount: it changes, so internally PHP assigns by reference until you actually change the assigned value. You can read about this in the blog post by nikic:

The important difference to PHP 5 is that all variables were able to share the same array, even though some were PHP references and some weren’t. Only once some kind of modification is performed the array will be separated.

Upvotes: 2

Related Questions