Стандарт PHP не поддерживает вложенные функции. Однако он поддерживает нечто, немного похожее на них. Вместо того чтобы, как и у переменных, ограничить область видимости для вложенных функций своими "родителями", PHP делает их доступными для всей остальной части программы, но только с того момента, когда "функция-родитель"
была из нее вызвана. Позднее, в части V книги, мы увидим, что этот (казалось бы) недочет оказывается довольно удобным способом для написания библиотек функций на PHP.
Итак, "вложенные" функции выглядят следующим образом (листинг 11.13):
Листинг 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);
Child(30);
// Ïîïðîáóéòå òåïåðü ÂÌÅÑÒÎ ýòèõ äâóõ âûçîâîâ ïîñòàâèòü òàêèå
// æå, íî òîëüêî â îáðàòíîì ïîðÿäêå. ×òî, âûäàåò îøèáêó?
// Почему, спрашиваете? Читайте дальше!
Мы видим, что нет никаких ограничений на место описания функции — будь то глобальная область видимости программы, либо же тело какой-то другой функции. В то же время, напоминаю, что понятия "локальная функция"
как такового в PHP все же (пока?) не существует.
Каждая функция добавляется во внутреннюю таблицу функций PHP тогда, когда управление доходит до участка программы, содержащего определение этой функции. При этом, конечно, само тело функции пропускается, однако ее имя фиксируется и может далее быть использовано в сценарии для вызова. Если же в процессе выполнения программы PHP никогда не доходит до определения некоторой функции, она не будет "видна", как будто ее и не существует — это ответ на вопросы, заданные внутри комментариев примера.
Давайте теперь попробуем запустить другой пример. Вызовем Parent() два раза подряд:
Parent(10);
Parent(20);
Последний вызов породит ошибку: функция Child()
уже определена. Это произошло потому, что Child() определяется внутри Parent(), и до ее определения управление программы фактически доходит дважды (при первом и втором вызовах Parent()). Поэтому-то интерпретатор и "протестует": он не может второй раз добавить Child() в таблицу функций.
Для тех, кто раньше программировал на Perl, этот факт может показаться ужасающим. Что ж, действительно, мы не должны использовать вложенные функции PHP так же, как делали это в Perl.