цикл 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 

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

Solutions Collecting From Web of "цикл foreach и ссылка & $ value"

В конце первого цикла $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: переход по ссылке

Это столкновение имен: имя $ 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); 

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

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

 $variable = [1,2,3,4]; foreach ($variable as $key => &$value) { $value++; } unset($value); var_dump($variable); с $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

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

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


 $variable = [1,2,3,4]; foreach ($variable as $key => &$value) { $value ++; } unset($value); foreach ($variable as $key => $value); print_r($variable); с $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. Рекомендуется уничтожить его unset ().

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

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

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

 unset($value); 

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

  $variable = [1,2,3,4]; foreach ($variable as $key => &$value) { $value++; } unset($value); var_dump($variable); с  $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 .

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

 <?php $array = [1, 2, 3, 4]; var_dump($array); $x = &$array[2]; var_dump($array); $x += 20; unset($x); var_dump($array); ?> с <?php $array = [1, 2, 3, 4]; var_dump($array); $x = &$array[2]; var_dump($array); $x += 20; unset($x); var_dump($array); ?> 

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

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

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

 <?php $x = 23; $ref = &$x; var_dump($x); ?> 

var_dump() не даст нам никакого намека.

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

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

 $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 между двумя циклами разрешает ситуацию. См. Также более ранний ответ от меня.