Недавно обнаружил не совсем логичное поведение конструкции foreach. Дело в том, что если в качестве плавающей переменной используется ссылка, используемая ранее, то она не сбрасывается, что ведет к непредсказуемому результату. Ниже приведен пример того, как это происходит. Пример разделен пустыми строками на несколько блоков. В первом блоке создается массив, заполненный целыми числами от 1 до 5. Во втором блоке этот массив выводится на экран. В третьем блоке самое интересное: иницируется сбой логики. И в четвертом блоке, как и во втором, массив выводится на экран. Код (Text): <pre><?php $a=range(1,5); //Array creating print_r($a); //Output of array: 1 foreach($a as &$b); //Bag source foreach($a as $b); print_r($a); //Output of array: 2 Казалось бы, мы должн получить два идентичных вывода одного массива, это следует из того, что между выводами нет ни одной операции присваивания. Но третий блок нарушает эту логику и выводы становятся разными. Этот баг повстречался в одном из моих скриптов. И я решил бороться с ним путем принудительного сбрасывания ссылки, вот-так: Код (Text): foreach($a as &$b); //Bag source unset($b); foreach($a as $b);
Это не баг, а кривизна рук. Для большего понимания можно переписать так: Код (Text): <pre> <?php $a=range(1,5); //Array creating print_r($a); //Output of array: 1 //foreach($a as &$b); //Bag source for ($i = 0; $i < count($a); $i++) { $b = &$a[$i]; } //foreach($a as $b); for ($i = 0; $i < count($a); $i++) { // $b - ссылка на последний элемент $a, т.е. $a[4]. $b = $a[$i]; // а это равнозначно $a[4] = $a[$i]; } print_r($a); //Output of array: 2 ?> </pre>
freeneutron я думаю это не какой не баг, просто $b - ссылка, при проследней итерации в цикле (при ключе равном 4, а значении равном 5) - устанавливается последнее значение $b - т.е. 4
http://bugs.php.net/bugstats.php Total bug entries in system: 48214 Closed Open All: 48214 23148 1810
Согласен, я немного перегнул палку. Сенсации здесь нет, и бага тоже нет... Просто принцыпы пхп можно трактовать по разному. Я свято верил, что foreach полностью переопределяет плавающую переменную, если она использовалась ранее. А Создатели пхп, да святится их имя, сделали ссылочный механизм максимально прозрачным. Но они могли бы занять и мою точку зрения, что рано или поздно, тоже привело бы к аналогичным противоречиям.
твой случай выделен в документации по foreach красной рамочкой: никто не виноват в том, что ты не читаешь документацию.
Это не мой случай. Только его половина. О второй половине, то есть о том, что foreach не переинициализирует $value, если $value евляется ссылкой, там ни чего не сказано. Там же в инструкции сказано, что foreach создает копию массива и работает с ней. Так почему бы, пользуясь здравым смыслом, не предположить, что foreach кроме копии массива создает и отдельную плавающую переменную, а не использует ту, на которую ссылается $value? Ведь это язык высокого уровня, в нем все должно быть интуитивно понятно и как можно меньше подводных камней...
Здесь сказано, что ссылка сохраняется после цикла. А в моем случае ссылка сохраняется еще и при входе в цикл, и об этом ни чего не сказано...
А эксперименты со скоростями: switch () { case } vs if ( || ) vs in_array() - это не фигня? Тот кто действительно знает основы наверно не парится...
freeneutron Реализации могут быть разными, поскольку это скриптовый язык - он не транслируется с ASM при компиляции. И не раз бывало что результат не совсем предсказуемый. К примеру я ожидал что switch{} case преобразовывается в hash таблицу и ему пофиг на кол-во элементов в случаях, когда все case статичны - т.е. он работать должен со скоростью простого if() - оказалось что казалось. Вы, уважаемый, оперируете не теми нагрузками - для вас +- десяток минут процессорного времени в сутки фигня, а для меня это легко может быть +- сервер. Или оптимизация запроса к базе на 0.1 ms может снизить нагрузку на базу в 2 раза потому что это самый частый запрос, который выполняется десятками миллионов раз в сутки - быстрее освобождаются блокировки, быстрее происходит обновление данных, меньше задержек - нагрузка падает. Таких мест много, они собираются по мелочам, но в итоге даёт существенную экономию тактов процессора в сутки если у вас высокая нагрузка 24/7/365. http://www.php.ru/forum/viewtopic.php?p=154974