За последние 24 часа нас посетили 19585 программистов и 1604 робота. Сейчас ищут 947 программистов ...

Сенсация! В пхп найден баг.

Тема в разделе "Прочие вопросы по PHP", создана пользователем freeneutron, 11 июн 2009.

  1. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    Недавно обнаружил не совсем логичное поведение конструкции foreach. Дело в том, что если в качестве плавающей переменной используется ссылка, используемая ранее, то она не сбрасывается, что ведет к непредсказуемому результату. Ниже приведен пример того, как это происходит. Пример разделен пустыми строками на несколько блоков.
    В первом блоке создается массив, заполненный целыми числами от 1 до 5.
    Во втором блоке этот массив выводится на экран.
    В третьем блоке самое интересное: иницируется сбой логики.
    И в четвертом блоке, как и во втором, массив выводится на экран.
    Код (Text):
    1. <pre><?php
    2. $a=range(1,5);      //Array creating
    3.  
    4. print_r($a);        //Output of array: 1
    5.  
    6. foreach($a as &$b); //Bag source
    7. foreach($a as $b);
    8.  
    9. print_r($a);        //Output of array: 2
    Казалось бы, мы должн получить два идентичных вывода одного массива, это следует из того, что между выводами нет ни одной операции присваивания. Но третий блок нарушает эту логику и выводы становятся разными.
    Этот баг повстречался в одном из моих скриптов. И я решил бороться с ним путем принудительного сбрасывания ссылки, вот-так:
    Код (Text):
    1. foreach($a as &$b); //Bag source
    2. unset($b);
    3. foreach($a as $b);
     
  2. mugabe

    mugabe Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1
    Симпатии:
    0
    Это не баг, а кривизна рук.

    Для большего понимания можно переписать так:
    Код (Text):
    1. <pre>
    2. <?php
    3. $a=range(1,5);      //Array creating
    4.  
    5. print_r($a);        //Output of array: 1
    6.  
    7. //foreach($a as &$b); //Bag source
    8.  
    9. for ($i = 0; $i < count($a); $i++) {
    10.     $b = &$a[$i];
    11. }
    12.  
    13. //foreach($a as $b);
    14.  
    15. for ($i = 0; $i < count($a); $i++) {
    16.     // $b - ссылка на последний элемент $a, т.е. $a[4].
    17.     $b = $a[$i];
    18.     // а это равнозначно $a[4] = $a[$i];
    19. }
    20.  
    21. print_r($a);        //Output of array: 2
    22. ?>
    23. </pre>
     
  3. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    подтверждаю, не баг - обычное поведение ссылок.
     
  4. sylex

    sylex Активный пользователь

    С нами с:
    9 ноя 2008
    Сообщения:
    625
    Симпатии:
    0
    Адрес:
    Омск
    freeneutron
    я думаю это не какой не баг, просто $b - ссылка, при проследней итерации в цикле (при ключе равном 4, а значении
    равном 5) - устанавливается последнее значение $b - т.е. 4
     
  5. iliavlad

    iliavlad Активный пользователь

    С нами с:
    24 янв 2009
    Сообщения:
    1.689
    Симпатии:
    4
    http://bugs.php.net/bugstats.php
    Total bug entries in system: 48214 Closed Open
    All: 48214 23148 1810
     
  6. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    Согласен, я немного перегнул палку. Сенсации здесь нет, и бага тоже нет...
    Просто принцыпы пхп можно трактовать по разному. Я свято верил, что foreach полностью переопределяет плавающую переменную, если она использовалась ранее. А Создатели пхп, да святится их имя, сделали ссылочный механизм максимально прозрачным. Но они могли бы занять и мою точку зрения, что рано или поздно, тоже привело бы к аналогичным противоречиям.
     
  7. твой случай выделен в документации по foreach красной рамочкой:
    никто не виноват в том, что ты не читаешь документацию.
     
  8. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    Это не мой случай. Только его половина. О второй половине, то есть о том, что foreach не переинициализирует $value, если $value евляется ссылкой, там ни чего не сказано. Там же в инструкции сказано, что foreach создает копию массива и работает с ней. Так почему бы, пользуясь здравым смыслом, не предположить, что foreach кроме копии массива создает и отдельную плавающую переменную, а не использует ту, на которую ссылается $value? Ведь это язык высокого уровня, в нем все должно быть интуитивно понятно и как можно меньше подводных камней...
     
  9.  
  10. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    Здесь сказано, что ссылка сохраняется после цикла. А в моем случае ссылка сохраняется еще и при входе в цикл, и об этом ни чего не сказано...
     
  11. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Просто автор не знает основ, вот и страдает фигнёй. Не зря есть вышкы по комп. наукам, ой не зря!
     
  12. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    А эксперименты со скоростями: switch () { case } vs if ( || ) vs in_array() - это не фигня? Тот кто действительно знает основы наверно не парится...
     
  13. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    freeneutron
    Реализации могут быть разными, поскольку это скриптовый язык - он не транслируется с ASM при компиляции. И не раз бывало что результат не совсем предсказуемый.
    К примеру я ожидал что switch{} case преобразовывается в hash таблицу и ему пофиг на кол-во элементов в случаях, когда все case статичны - т.е. он работать должен со скоростью простого if() - оказалось что казалось.
    Вы, уважаемый, оперируете не теми нагрузками - для вас +- десяток минут процессорного времени в сутки фигня, а для меня это легко может быть +- сервер. Или оптимизация запроса к базе на 0.1 ms может снизить нагрузку на базу в 2 раза потому что это самый частый запрос, который выполняется десятками миллионов раз в сутки - быстрее освобождаются блокировки, быстрее происходит обновление данных, меньше задержек - нагрузка падает.

    Таких мест много, они собираются по мелочам, но в итоге даёт существенную экономию тактов процессора в сутки если у вас высокая нагрузка 24/7/365.

    http://www.php.ru/forum/viewtopic.php?p=154974
     
  14. freeneutron

    freeneutron Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    226
    Симпатии:
    3
    Мне есть что сказать о хайлоаде, но нет настроения. Так, что ни сегодня и не в этом топике...
     
  15. Да, да. Тебе нас жаль.