Подтвердить что ты не робот

Цикл foreach и ссылка & $value

Почему пустой цикл foreach может изменить результат.

У меня есть следующий код:

  $variable = [1,2,3,4];
  foreach ($variable  as $key => &$value) 
    $value ++;
  var_dump($variable);

В результате получается

  array (size=4)
  0 => int 2
  1 => int 3
  2 => int 4
  3 => &int 5

Теперь, когда я добавляю пустой цикл foreach, подобный этому

  $variable  = [1,2,3,4];
  foreach ($variable  as $key => &$value) 
    $value ++;
  foreach ($variable  as $key => $value);
  var_dump($variable);

Я получаю это:

 array (size=4)
 0 => int 2
 1 => int 3
 2 => int 4
 3 => &int 4

может кто-нибудь объяснить мне, почему последний элемент не изменяется, когда я добавляю второй пустой цикл, и почему существует и перед последним элементом?

4b9b3361

Ответ 1

В конце первого цикла $value указывает на то же место, что и $variable[3] (они указывают на то же место в памяти):

$variable  = [1,2,3,4];
foreach ($variable  as $key => &$value) 
    $value ++;

Даже когда этот цикл закончен, $value по-прежнему является ссылкой, указывающей на то же место в памяти, что и $variable[3], поэтому каждый раз, когда вы сохраняете значение в $value, это также перезаписывает значение, сохраненное для $variable[3]:

foreach ($variable as $key => $value);
var_dump($variable);

При каждой оценке этого foreach оба $value и $variable[3] становятся равными значению итерабельного элемента в переменной $.

Итак, в третьей итерации второго цикла $value и $variable[3] становятся равными 4 по ссылке, то в течение 4-й и последней итерации второго цикла ничего не меняется, потому что вы передаете значение $variable[3] (который все еще &$value) до $value (который все еще &$value).

Это очень сбивает с толку, но это даже не очень своеобразно; это код, выполняемый точно так, как должен.

Дополнительная информация здесь: PHP: переход по ссылке

Ответ 2

Это столкновение имен: имя $value, введенное в первом цикле, существует после него и используется во втором цикле. Таким образом, все присваивания ему фактически присваиваются исходному массиву. То, что вы сделали, легче наблюдать в этом коде:

  $variable = [1,2,3,4];
  foreach ($variable  as $key => &$value) 
    $value ++;
  $value = 123; // <= here you alter the array!
  var_dump($variable);

и вы увидите $variable[3] как 123.

Один из способов избежать этого, как говорили другие, - unset ($value) после цикла, что должно быть хорошей практикой, как рекомендовано в руководстве. Другой способ - использовать другую переменную во втором цикле:

  $variable  = [1,2,3,4];
  foreach ($variable  as $key => &$value) 
    $value ++;
  foreach ($variable  as $key => $val);
  var_dump($variable);

который не изменяет ваш массив.

Ответ 3

Последний элемент массива будет remian даже после цикла foreach. Поэтому необходимо использовать функцию unset вне цикла. Это

$variable  = [1,2,3,4];
  foreach ($variable  as $key => &$value) {
$value++;


}
  unset($value);
  var_dump($variable); 

Ссылка на руководство находится здесь http://php.net/manual/en/control-structures.foreach.php

Ответ 4

Как phil указано в комментариях:

Как указано в руководстве, после использования следует отключить() ссылки.


$variable  = [1,2,3,4];

foreach ($variable  as $key => &$value)  {
  $value ++;
}
unset($value);

foreach ($variable  as $key => $value);


print_r($variable);

Вернется:

Array
(
    [0] => 2
    [1] => 3
    [2] => 4
    [3] => 5
)

Пример


Объяснение

Взято из руководства foreach(). (Смотрите большой красный ящик)

Ссылка на значение $и последний элемент массива остаются даже после foreach loop. Рекомендуется уничтожить его unset().

В основном это означает: что ссылочное значение &$value и последний элемент/элемент в массиве, который в этом случае равен 4, остаются неизменными. Чтобы противодействовать этой проблеме, вы должны будете unset() значение после использования, иначе оно останется в массиве в качестве исходного значения (если это имеет смысл).

Вы также должны прочитать следующее: Как работает PHP foreach?

Ответ 5

После цикла вы должны отключить эту ссылку, используя:

unset($value);

Таким образом, весь ваш код должен работать следующим образом:

  $variable  = [1,2,3,4];
  foreach ($variable  as $key => &$value) {
    $value++;
  }
  unset($value);
  var_dump($variable); 

Нет смысла ставить unset($value); внутри цикла

Объяснение - после цикла значение $по-прежнему устанавливается в последний элемент массива, поэтому вы можете использовать его после цикла $value = 10; (перед отключением), и вы увидите, что последний элемент массива был изменен на 10. Кажется, что var_dump хочет немного помочь нам в этом случае и показывает, что есть ссылка для последнего элемента, и, конечно, когда мы используем unset, у нас есть желаемый вывод var_dump.

Вы также можете посмотреть следующий script:

<?php
  $array = [1, 2, 3, 4];

  var_dump($array);

  $x = &$array[2];

  var_dump($array);

  $x += 20;

  unset($x);

  var_dump($array);

?>

Мы не используем здесь цикл, и если для ссылки задан элемент массива, var_dump показывает нам это помещение & перед типом этого элемента.

Однако, если приведенный выше код мы изменили ссылку и установили его таким образом $x = &$array; var_dump не показывал нам никакой ссылки.

Также в следующем коде:

<?php
$x = 23;
$ref = &$x;

var_dump($x);

?>

var_dump() не даст нам никакой подсказки.

Ответ 6

Обязательное утверждение: ссылки злы!

Выполнение кода:

$variable  = [1,2,3,4];
foreach ($variable  as $key => &$value) 
    $value++;

После завершения цикла; $value является ссылкой на $variable[3] и, следовательно, имеет значение int(4).

foreach ($variable as $key => $value);

На каждой итерации $variable[3] получает элемент $variable[<k>], где 0 <= k < 3. На последней итерации ему присваивается собственное значение, которое соответствует предыдущей итерации, поэтому оно int(4).

Отключение $value между двумя контурами разрешает ситуацию. См. Также более ранний ответ.