Pull to refresh

Comments 19

foreach ($test AS &$value) {
// какие-то действия. Но для теста и пустого цикла достаточно
}

думаю что эти «какие-то действия» как раз и изменили в Вашем примере значение с ключом 5
там ничего кроме этого комментария не надо делать, все равно 4 в конце, попробуйте сами
ua2.php.net/manual/ru/control-structures.foreach.php

Особенно стоит обратить внимание на:

Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().
попробуйте так:
$test = array('1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5);

foreach ($test AS &$value) {
// какие-то действия. Но для теста и пустого цикла достаточно
}

unset($value);

print_r($test);
foreach ($test AS $key => $value) {
echo "{$key} => {$value}\n";
}
Да, это помогает. Но механизм все равно не понятен. Почему имеено последняя итерация ссылается на предпоследний элемент? Почему не первая?
после первового foreach'а $value является ссылкой на последний элемент массива
во втором foreach'е происходит следующее:
на первой итерации $value присваивается значение первого элемента массива (а значит и его последнему элементу тоже), то есть массив уже выглядит так: 1 2 3 4 1
на второй итерации $value=2, то бишь массив — 1 2 3 4 2
на третьей итерации — 1 2 3 4 3
на четвертой — 1 2 3 4 4
а на пятой — пятому элементу массива присваивается значение пятого (а сейчас 5 элемент — 4)

вот как-то так
Т.е. после первого цикла $value всегда остается «указателем» на последний элемент массива. А во втором цикле туда по очереди пишутся все значения массива, каждый раз перетирая последний элемент.
Это я для себя перефразировал, может кому-нибудь тоже поможет понять.
Довольно неожиданно, но я думаю что это как-то объясняется (ведь интерпритатор руководствуется какой-то логикой?).

ОФФ. Цикл foreach плохо влияет на производительность — во время прогона элементов он создает в памяти копию исходного массива и оперирует с ней, после чего удаляет (цитата с php.net «foreach operates on a copy of the specified array and not the array itself»). Вместо него лучше-таки использовать while:

while(list($key, $val) = each($array)){… } reset($array);

Не удобно. А экономить на спичках глупо.
Экономия на спичках — это замена двойных кавычек на одинарные (например). А тут, если исходный массив будет несколько мегабайт, то создавать его копию уже точно не умно.
Но не будем спорить :) Спасибо за фишку, буду знать теперь!
foreach читабельнее. а когда захочется его немного ускорить, то тут уже можно заняться оптимизацией.

перефразируя: «не оптимизируй то, что не тормозит»
Как я понимаю, копия делается только по требованию. По крайней мере ни раз читал, что копия аргументов функции делается толко при попытке изменить их. Было бы логично в циклах сделать так-же.
Тут уже проскакивала не раз ссылка на phpbench.com

Так вот там утверждается что для чтения foreach примерно в 5-7 раз быстрее чем while (list… each..)
А вот если вы собираетесь изменять исходный массив, то тут конечно foreach сильно отстает.
Тут дело не в скорости, а в удвоенном объеме памяти занимаемым на проход цикла.
[8 Oct 2004 8:54am UTC] derick@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
www.php.net/manual/ and the instructions on how to report
a bug at bugs.php.net/how-to-report.php

Right, thanks for that analysis. No bug here. (And no, we can't unset it
by default, as people might use this for some weird reason).
да что-же тут непонятного.
хоть это и неудобно, но логически все верно.

tFirma все правильно сказал

если вы пользуетесь фичами языка не понимая как они работают — это ваши проблемы.
Я бы назвал эту статью «будьте внимательнее с указателями»
Sign up to leave a comment.

Articles