2

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?

Xriuk
  • 429
  • 5
  • 16
  • At first, using the same variable `$tmp`, you overwrite its value. Inside your loop, the variable `$tmp` keeps the last value of the array `$path`. – KubiRoazhon Feb 19 '19 at 10:38
  • No, `$tmp` is used to keep track of point of the array where I am now. So at first `$tmp` will be the whole array `$arr`, then it will be `$arr["lvl1"]`, then `$arr["lvl1"]["lvl2"]` and so on. What I'm asking is: everytime I go deeper, do I make copies of the array(s) or am I still accessing the original one (`$arr`)? – Xriuk Feb 19 '19 at 10:52
  • each time it will modify `$tmp` value as `$tmp[$lvl]` – Omi Feb 19 '19 at 11:38
  • Possible duplicate of [How does PHP 'foreach' actually work?](https://stackoverflow.com/questions/10057671/how-does-php-foreach-actually-work) – 5eeker Feb 19 '19 at 11:39
  • @5eeker Ehm, no, I'm not asking about foreach loop, I'm asking about reusing the same variable multiple times to get deeper. – Xriuk Feb 19 '19 at 12:11
  • @Omi Ok, but each time `$tmp` will be a copied array or a reference to `$arr`? I mean under the hood, if I don't write anything. – Xriuk Feb 19 '19 at 12:12
  • 1
    no it just the copied array – Omi Feb 19 '19 at 12:13
  • @Omi And using references won't help? If I did: `$tmp = &$tmp[$lvl]` would it change? – Xriuk Feb 19 '19 at 12:17
  • yes then it will reference to `&$tmp[$lvl]` so the change in `&$tmp[$lvl]` would reflect in `$tmp` also but note you are changing `$tmp` value each time so it will be not your original array – Omi Feb 19 '19 at 12:24
  • @Omi Yes, but I don't care about changing it. I was wondering if it would copy the array parts everytime, it shouldn't do that when referencing, right? – Xriuk Feb 19 '19 at 12:29
  • yes, every time it override array value with new value – Omi Feb 19 '19 at 12:32

1 Answers1

2

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.

Community
  • 1
  • 1
sevavietl
  • 3,762
  • 1
  • 14
  • 21
  • Thank you! That's what I was looking for! So this only happens in PHP7? To get a similar effect before PHP7 I would have to use references manually, right? – Xriuk Feb 20 '19 at 12:27
  • 1
    @Xriuk I guess, PHP 5 will do the same. You can find really old articles regarding **copy-on-write** concept in PHP. To be sure you can run the code I have provided on your environment and see `refcount`'s for yourself. – sevavietl Feb 20 '19 at 12:42