PHP обращается к вложенным массивам, копируя их? - PullRequest
0 голосов
/ 19 февраля 2019

Допустим, у меня есть массив (он действительно может иметь любую глубину):

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

Теперь в функции мне нужно получить к ней доступ следующим образом:

$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];
}

На этомно, просто из любопытства (здесь нет никакой реальной оптимизации), я делаю копий копий каждый раз?Или это просто использование ссылок автоматически?

1 Ответ

0 голосов
/ 20 февраля 2019

TL; DR Если вы используете PHP 7, массив не будет скопирован внутри, если вы его не измените.Это называется копирование при записи .

Чтобы понять, как работает PHP под капотом, вы можете прочитать Основы подсчета ссылок :

Переменная PHP хранится в контейнере, называемом "zval".

PHP достаточно умен, чтобы не копировать реальный контейнер переменных, когда в этом нет необходимости.

Давайте попробуем проиллюстрировать это на вашем упрощенном примере, используя 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);

Если вы запустите этот код, вы получите следующий вывод:

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){
      }
    }
  }
}

Обратите внимание на refcount: он меняется, поэтому внутренне PHP назначается по ссылке, пока вы фактически не измените назначенное значение.Вы можете прочитать об этом в сообщении в блоге от nikic :

Важным отличием от PHP 5 является то, что все переменные могли совместно использовать один и тот же массив, хотя некоторые из них были PHPссылки и некоторые не были.Только после выполнения какой-либо модификации массив будет разделен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...