У меня просто было очень странное поведение с простым скриптом php, который я писал. Я уменьшил его до минимума, необходимого для воссоздания ошибки:
<?php $arr = array("foo", "bar", "baz"); foreach ($arr as &$item) { /* do nothing by reference */ } print_r($arr); foreach ($arr as $item) { /* do nothing by value */ } print_r($arr); // $arr has changed....why? ?>
Эти результаты:
Array ( [0] => foo [1] => bar [2] => baz ) Array ( [0] => foo [1] => bar [2] => bar )
Это ошибка или какое-то действительно странное поведение, которое должно произойти?
После первого цикла foreach $item
все еще является ссылкой на некоторое значение, которое также используется $arr[2]
. Поэтому каждый вызов foreach во втором цикле, который не вызывает по ссылке, заменяет это значение и, таким образом, $arr[2]
, с новым значением.
Итак, цикл 1, значение и $arr[2]
становятся $arr[0]
, что является «foo».
Loop 2, значение и $arr[2]
становятся $arr[1]
, что является «баром».
Петля 3, значение и $arr[2]
становятся $arr[2]
, что является «баром» (из-за цикла 2).
Значение «baz» фактически теряется при первом вызове второго цикла foreach.
Для каждой итерации цикла мы будем эхо-значения $item
а также рекурсивно печатать массив $arr
.
Когда первый цикл выполняется, мы видим этот вывод:
foo Array ( [0] => foo [1] => bar [2] => baz ) bar Array ( [0] => foo [1] => bar [2] => baz ) baz Array ( [0] => foo [1] => bar [2] => baz )
В конце цикла $item
все еще указывает на то же место, что и $arr[2]
.
Когда выполняется второй цикл, мы видим этот вывод:
foo Array ( [0] => foo [1] => bar [2] => foo ) bar Array ( [0] => foo [1] => bar [2] => bar ) bar Array ( [0] => foo [1] => bar [2] => bar )
Вы заметите, как каждый раз массив помещал новое значение в $item
, он также обновлял $arr[3]
с тем же значением, поскольку оба они все еще указывают на одно и то же местоположение. Когда цикл попадает в третье значение массива, он будет содержать bar
значений, потому что она была просто установлена предыдущей итерацией этого цикла.
Нет. Это поведение ссылочного элемента, а не ошибка. Это было бы похоже на запуск чего-то вроде:
for ($i = 0; $i < count($arr); $i++) { $item = $arr[$i]; }
Цикл foreach не является особым по своему характеру, в котором он может игнорировать ссылочные позиции. Это просто устанавливает эту переменную в новое значение каждый раз, как если бы вы были вне цикла.
$item
является ссылкой на $arr[2]
и перезаписывается вторым циклом foreach, как указывал animuson.
foreach ($arr as &$item) { /* do nothing by reference */ } print_r($arr); unset($item); // This will fix the issue. foreach ($arr as $item) { /* do nothing by value */ } print_r($arr); // $arr has changed....why?
сforeach ($arr as &$item) { /* do nothing by reference */ } print_r($arr); unset($item); // This will fix the issue. foreach ($arr as $item) { /* do nothing by value */ } print_r($arr); // $arr has changed....why?
Хотя это может быть официально не ошибкой, на мой взгляд, это так. Я думаю, что проблема здесь в том, что мы ожидаем, что $item
выйдет из области действия, когда цикл будет завершен, как и во многих других языках программирования. Однако, похоже, это не так …
Этот код …
$arr = array('one', 'two', 'three'); foreach($arr as $item){ echo "$item\n"; } echo $item;
Дает результат …
one two three three
Как уже говорили другие люди, вы переписываете ссылочную переменную в $arr[2]
вторым циклом, но это происходит только потому, что $item
никогда не выходил за рамки. Что вы, ребята, думаете … ошибка?
Более легкое объяснение, похоже, от Rasmus Lerdorf, оригинального создателя PHP: https://bugs.php.net/bug.php?id=71454
Правильное поведение PHP может быть ошибкой NOTICE в моем оппионе. Если ссылочная переменная, созданная в цикле foreach, используется вне цикла, она должна вызывать уведомление. Очень легко пасть за это поведение, очень сложно определить его, когда это произошло. И ни один разработчик не собирается читать страницу документации foreach, это не поможет.
Вы должны unset()
ссылку после цикла, чтобы избежать такой проблемы. unset () по ссылке просто удалит ссылку без ущерба для исходных данных.