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

Постфиксный декремент, стат. переменные

Тема в разделе "PHP для новичков", создана пользователем iNEEdhLw, 20 янв 2015.

  1. iNEEdhLw

    iNEEdhLw Новичок

    С нами с:
    22 окт 2014
    Сообщения:
    414
    Симпатии:
    0
    читал мануал и наткнулся на простенький листинг, который привожу ниже (добавил переводы строк и вардамп):
    Код (Text):
    1. <?php
    2. function test()
    3. {
    4.     static $count = 0;
    5.  
    6.     $count++;
    7.     echo $count."<br>";
    8.    
    9.     if ($count < 10) {
    10.         test();
    11.     }
    12.     $count--;
    13.     echo "<br>";
    14.     var_dump($count); //решил проверить результат
    15. }
    16. test();
    в ответ на что получаю следующее :
    на мануале про такое нечего не заметил. ведь декремент/инкремент увеличивает/уменьшает на 1 ед., а не до 0.
    объясните или киньте почитать чего-то, я удивлен.
    з.ы. знаю, что вопрос даунский, но не могу понять причину такого рез-та. только догадки
     
  2. immortal.1986

    immortal.1986 Активный пользователь

    С нами с:
    24 сен 2013
    Сообщения:
    257
    Симпатии:
    0
    похоже на рекусию!
     
  3. iNEEdhLw

    iNEEdhLw Новичок

    С нами с:
    22 окт 2014
    Сообщения:
    414
    Симпатии:
    0
    рекурсия выполняется при условии, что $count < 10, а когда эта переменная достигает цифры 10, то вызов рекурсии должен опускаться и происходить декремент на 1 единицу, - в моем понимании ситуации.

    Добавлено спустя 36 секунд:
    в данном случаем ведь рекурсия только увеличивает постепенно $count
     
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Тут все очень просто. Пока $count не дойдет до 10, функция будет раз за разом сваливаться в саму себя, увеличивая значение. При этом остальной код в функции выполняться не будет. Он будет ждать, пока ранее вызванная функция не закончит работу.
    В итоге у тебя порождается очередь из 10 подряд ожидающих декрементов. Не одного, а десяти. Они и откатывают переменную в ноль.

    Попробуй на листочке нарисовать функцию как прямоугольник, а из середины выходит стрелочка в такой же прямоугольник, из середины которого выходит стрелочка...

    Все, что ниже точки, из которой выходит стрелочка, ждет, пока отработает то, куда стрелочка показывает. И сначала отработают все фрагменты до стрелочки от первого прямоугольника до последнего. А потом отработают все фрагменты после стрелочки, от последнего прямоугольника до первого. Это называется коллстэк или стэк вызовов. Именно стэк, а не очередь, обрати внимание. Очередь - это FIFO, first input, first output , стэк - это LIFO, last input, first output. Рекурсивные вызовы функции порождают именно вложенность. Они работают не параллельно.

    При вызове любой функции, в коллстэк подается соответствующая запись. По завершению функции, запись снимается. При этом данные, созданные в элементе, который имеет уровень иерархии выше остаются в оперативной памяти. Об этом очень важно помнить.
     
  5. iNEEdhLw

    iNEEdhLw Новичок

    С нами с:
    22 окт 2014
    Сообщения:
    414
    Симпатии:
    0
    т.е. по сути рекурсивные функции работают как стек?
    на данном примере с листингом я понял, как это работает, но
    вот в моей предыдущей теме (про факториал) я использовал опять рекурсию.
    Код (Text):
    1.  function factorial($number)
    2. {
    3.    if ($number == 0 or $number ==1) return 1;
    4.    $result = $number*factorial($number-1);
    5.    return $result;
    6.    
    7. }
    значит, что $result будет ожидать n-количество... не знаю, как назвать, проходов?... функции.
    в данном случае это тоже стек, ведь в обратном порядке порядке ему нечего отдавать не нужно.
    запутался :(
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.598
    Симпатии:
    1.764
    Функции всегда через стек работают. Из стека берутся аргументы, ту да же помещаются локальные переменные. У вас тут локальная переменная $result и параметр $number. Даже если функция не рекурсивная, эти значения интерпретатор поместит в стек. И только благодаря этой особенности рекурсия вообще возможна и полезна.

    [offtop]
    Помню, в ВУЗе препод никак не мог рассказать группе, чтоб все поняли, как работает алгоритм обхода бинарного дерева. А я это уже знал. И он был очень удивлён, когда я встал, и нарисовал на доске стек, как меняется в процессе работы алгоритма вершина стека, и т.п.
    [/offtop]
     
  7. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Нет, он будет ожидать ровно один. Там прописан ровно один вызов. И он его ждет. Ему плевать, что там внутри.
    А внутри еще один $result и он ждет еще один вызов. И так вглубь.

    Потом, когда последняя вложенная функция отработала, она отдает свой результат наверх. Там, он, согласно твоей формуле, умножается на $number и передается наверх, там, он, согласно твоей формуле...

    В итоге ты собираешь урожай в виде конечного результата.
     
  8. iNEEdhLw

    iNEEdhLw Новичок

    С нами с:
    22 окт 2014
    Сообщения:
    414
    Симпатии:
    0
    всё, теперь понял.
    визуально подобрал себе иллюстрацию, с помощью которой легче осознать это :)
    спасибо