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