Оператор PHP foreach по ссылке: неожиданное поведение при повторном использовании итератора

этот код выдает неожиданный результат:

$array=str_split("abcde");
foreach($array as &$item)
    echo $item;

echo "\n";
foreach($array as $item)
    echo $item;

выход:

abcde
abcdd

если использовать &$item для второго цикла, все работает нормально.

Я не понимаю, как этот код повлияет на содержимое $array. Я мог бы подумать, что неявное unset($header) удалит последнюю строку, но откуда взялось двойное dd?


person Frederic Bazin    schedule 09.06.2011    source источник


Ответы (1)


Это может помочь:

$array=str_split("abcde");
foreach($array as &$item)
    echo $item;

var_dump($array);

echo "\n";
foreach($array as $item) {
    var_dump($array);
    echo $item;
}

Как вы можете видеть после последней итерации, $item относится к 4-му элементу $array (e).

После этого вы перебираете массив и заменяете 4-й элемент на текущий. Итак, после первой итерации второго цикла это будет abcda и т. д. до abcdd. И в последней итерации вы меняете 4-й элемент на 4-й, как d на d

person zerkms    schedule 09.06.2011
comment
Спасибо. Можно ли как-то отсоединить $item от 4-го элемента после первого цикла? - person Frederic Bazin; 09.06.2011
comment
@lenzai: unset($item); --- обычной практикой является сбрасывать ссылочную переменную, если она вам больше не нужна, чтобы предотвратить такую ​​путаницу. - person zerkms; 09.06.2011
comment
моя ошибка, я думал, что unsset($item удалит $array[4]. Наверное, я ошибался. - person Frederic Bazin; 09.06.2011
comment
@lenzai: unset всегда уничтожает ссылку. Если у вас есть $a = 1; unset($a);, он уничтожает единственную ссылку на 1, размещенную в памяти. Пока нет других ссылок - 1 больше не доступен ни с каким именем переменной, поэтому вы считаете ее неустановленной. Так что думайте о unset как о какой-то конструкции, которая разрывает взаимосвязь между именем переменной и памятью, но не изменяет память. - person zerkms; 09.06.2011
comment
Фактически, документация foreach (php.net/manual/en/control- Structures.foreach.php) специально говорит об этом: ссылка на значение $ и последний элемент массива остаются даже после цикла foreach. Рекомендуется уничтожить его с помощью unset(). - person newacct; 07.01.2013