Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 [ 64 ] 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

вложенные функции

Стандарт PHP не поддерживает вложенные функции. Однако он поддерживает нечто, немного похожее на них. Вместо того чтобы, как и у переменных, ограничить область видимости для вложенных функций своими "родителями", PHP делает их доступными для всей остальной части программы, но только с того момента, когда "функция-родитель" была из нее вызвана. Позднее, в части V книги, мы увидим, что этот (казалось бы) недочет оказывается довольно удобным способом для написания библиотек функций на PHP.

Итак, "вложеннхе" функции вхглядят следующим образом (листинг 11.13):

i Листинг 11.13. Вложенные функции

function Parent($a) { echo $a;

function Child($b)

{ echo $b+1;

return $b*$b;

return $a*$a*Child($a); фактически возвращает $a*$a*($a+1)*($a+1)

Вызываем функции Parent(10);

всего дерева каталогов вашего сервера (с целью подсчитать суммарный объем, который занимают все файлы), или для других задач. Рассмотрим для примера функцию, которая рекурсивно вычисляет факториал из некоторого числа n (обозначается n! ). Алгоритм стандартный: если n=0, то n!=1, а иначе n!=n*((n-1)!).

function Factor($n)

{ if($n<=0) return 1;

else return $n*Factor($n-1);

echo Factor(20);

Должен только предупредить вас не применять эту функцию факториала в реальной жизни - она приведена здесь исключительно для примера. Лучше воспользоваться следующей функцией - она работает гораздо быстрее:

function Factor($n) { for($f=1; $n>1; $n-) $f*=$n; return $f;



( Замечание

Для тех, кто раньше программировал на Perl, этот факт может показаться ужасающим. Что ж, действительно, мы не должны использовать вложенные функции PHP так же, как делали это в Perl.

Условно определяемые функции

Предположим, у нас в программе где-то устанавливается переменная $os type в значение win, если сценарий запущен под Windows 9x, и в unix, если под Unix. Как известно, в отличие от Unix, в Windows нет такого понятия, как владелец файла, а значит, стандартная функция chown() (которая как раз и назначает владельца для указанного файла) там просто не имеет смысла. В некоторых версиях PHP для Windows ее может в этой связи вообще не быть. Однако, чтобы улучшить переносимость сценариев с одной платформы на другую (без изменения их кода!) можно написать следующую простую "обертку" для функции chown() (листинг 11.14):

Child(30);

Попробуйте теперь ВМЕСТО этих двух вызовов поставить такие же, но только в обратном порядке. Что, в1дает ошибку? Почему, спрашиваете? Читайте дальше!

Мы видим, что нет никаких ограничений на место описания функции - будь то глобальная область видимости программы, либо же тело какой-то другой функции. В то же время, напоминаю, что понятия "локальная функция" как такового в PHP все же (пока?) не существует.

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

Давайте теперь попробуем запустить другой пример. Вызовем Parent() два раза подряд:

Parent(10); Parent(20);

Последний вызов породит ошибку: функция Child() уже определена. Это произошло потому, что Child() определяется внутри Parent() , и до ее определения управление программы фактически доходит дважды (при первом и втором вызовах Parent() ). Поэтому-то интерпретатор и "протестует": он не может второй раз добавить Child() в таблицу функций.



i Листинг 11.14. Условно определяемые функции

if($OS TYPE=="win") { Функция-заглушка

function MyChOwn($fname,$attr)

{ ничего не делает return 1;

else

{ Передаем вызов настоящей chown() function MyChOwn($fname,$attr) { return chown($fname,$attr); }

Это - один из примеров условно определяемых функций. Если мы работаем под Windows, функция MyChOwn() ничего не делает и возвращает 1 как индикатор успеха, в то время как для Unix она просто вызывает оригинальную chown(). Важно то, что проверка, какую функцию использовать, производится только один раз (в момент прохождения точки определения функции), т. е. здесь нет ни малейшей потери производительности. Теперь в сценарии мы должны всюду отказаться от chown() и использовать MyChOwn() (можно даже провести поиск/замену этого имени в редакторе) - это обеспечит переносимость.

Если вам совсем не нравится идея поиска/замены (а мне она не нравится категорически), то существует гораздо более элегантный способ, но только в том случае, если chown() еще не была нигде определена - в том числе и среди стандартных функций:

if(!function exists("chown")) { function chown($fname,$mode) { не делаем ничего return 1;

Этот способ работает независимо от того, появится ли вдруг в будущих версиях PHP для Windows "заглушка" для функции chown(), или же нет. (Нужно сказать для справедливости, что в PHP версии 4 такая заглушка уже существует.)

Знатоки Си могут заметить в приеме условно определяемых функций разительное сходство с директивами условной компиляции этого языка: #ifndef, #else и #endif. Действительно, аналогия почти полная, за исключением того факта, что в Си



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 [ 64 ] 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189