Page 53 - 4636
P. 53

У цьому лістингу представлені реалізації двох функцій. Обидві вони виводять рядок у зворотному
        порядку. Функція reverse(r) - рекурсивна, reverse_i() - ітеративна.
           Функція  reverse_r()  приймає  рядок  як  параметр.  При  її  виклику  вона  буде  викликати  саму
        себе, щоразу передаючи символи рядка з другого до останнього.
           Наприклад, якщо викликати функцію таким чином:
           reverse_r('победа’);
           вона викличе себе шість раз з наступними параметрами:
           reverse_r('обеда');
           reverse_r('беда');
           reverse_r (’еда’);
           reverse_r ('да');
           reverse_r ('а');
           reverse_r ('');
           При кожному виклику самої себе функція створює нову копію коду функції в пам'яті сервера, але з
        іншим параметром. Зовні це виглядає так, немов насправді кожен раз викликається інша функція. Це
        запобігає виникнення плутанини з екземплярами функції.
           При  кожному  виклику  перевіряється  довжина  переданого  рядка.  Після  досягнення  кінця  рядка
        умова  виявляється  хибною  (strlen()  ==  0).  Після  цього  останній  екземпляр  функції
        (reverse_r('  '))  продовжить  роботу  і  виконає  наступний  рядок  коду,  тобто  виведе  на  екран
        перший  символ  переданої  рядка  -  в  даному  випадку  ніякого  виведення  не  буде,  оскільки  порожній
        рядок.
           Потім  цей  примірник  функції  повертає  управління  примірнику,  який  викликав  його,  а  саме,
        reverse_r('а  ').  Цей  екземпляр  виводить  перший  символ  у  своєму  рядку  ‘а',  і  повертає
        управління викликавшому його екземпляру.
           Згаданий процес - виведення символу та повернення до екземпляра функції, розташованого над ним
        у  порядку  виклику,  -  продовжується  до  того  часу,  поки  управління  не  буде  повернуто  основній
        програмі.
           Рекурсивні  рішення  вельми  витончені  і  відповідають  методам  математичної  рекурсії.  Проте  в
        більшості випадків краще використовувати ітераційні рішення. Код для реалізації цього методу також
        показаний в лістингу 2.3. Зверніть увагу, що за довжиною він не перевищує рекурсивний варіант (хоча
        при використанні ітеративних функцій це не завжди так) і виконує ті ж дії.
           Основна відмінність між ними полягає в тому, що рекурсивна функція створює в пам'яті копії самої
        себе  і,  відповідно,  призводить  до  непродуктивних  витрат  ресурсів,  які  обумовлені  багаторазовими
        викликами однієї і тієї ж функції.
           Рекурсивне  рішення  має  сенс  використовувати,  коли  відповідний  код  виявляється  набагато
        коротший і витонченіший від ітеративної версії, але в даній області застосування подібне трапляється
        нечасто.
           Хоча рекурсія виглядає більш елегантно, програмісти часто забувають визначити умову завершення
        рекурсії.  Це  означає,  що  функція  буде  продовжувати  викликати  себе  до  того  часу,  поки  сервер  не
        зіткнеться з нестачею пам'яті або поки не закінчиться максимальний час виконання, залежно від того,
        що станеться раніше.
           Простори імен
           У  загальному  випадку  простір  імен  (namespace)  -  це  абстрактний  контейнер  для  групи
        ідентифікаторів.  У  РНР  це  означає,  що  простір  імен  може  містити  певні  вами  функції,  константи  і
        класи. Створення просторів імен має декілька організаційних переваг для власних функцій і визначень
        класів:
             на  початок  імен  функцій,  класів  і  констант  у  просторі  імен  автоматично приписується  назва
        цього простору імен;
             непоточнені імена класів, функцій і констант вирішуються під час виконання, причому пошук
        спочатку виконується в просторі імен, а потім у глобальному просторі.


                                                            50
   48   49   50   51   52   53   54   55   56   57   58