В JavaScript вложенные функции очень полезны: закрытие, частные методы и что у вас есть.
Для чего нужны вложенные функции PHP? Кто-нибудь их использует и зачем?
Вот небольшое исследование, которое я сделал
<?php function outer( $msg ) { function inner( $msg ) { echo 'inner: '.$msg.' '; } echo 'outer: '.$msg.' '; inner( $msg ); } inner( 'test1' ); // Fatal error: Call to undefined function inner() outer( 'test2' ); // outer: test2 inner: test2 inner( 'test3' ); // inner: test3 outer( 'test4' ); // Fatal error: Cannot redeclare inner()
В основном нет, я всегда рассматривал это как побочный эффект парсера.
Эран Гальперин ошибочно полагает, что эти функции как-то закрыты, они просто не объявлены, пока не будет запущен outer()
. Они также не являются частным образом охвачены, они действительно оспаривают глобальный охват, хотя и задерживаются. И в качестве обратного вызова внешний обратный вызов еще может быть вызван только один раз. Я до сих пор не вижу, как это полезно применить к массиву, который, скорее всего, вызывает псевдоним более одного раза.
Единственным примером «реального мира», который я мог бы выкопать, является тот, который может работать только один раз и может быть переписан более чистым ИМО.
Единственное, что я могу придумать, это модули для вызова метода [name] _include, который устанавливает несколько вложенных методов в глобальном пространстве в сочетании с
if (!function_exists ('somefunc')) { function somefunc() { } }
чеки.
Очевидно, что ООП PHP будет лучшим выбором 🙂
Если вы используете PHP 5.3, вы можете получить больше поведения, подобного Javacript, с анонимной функцией:
<?php function outer() { $inner=function() { echo "test\n"; }; $inner(); } outer(); outer(); inner(); //PHP Fatal error: Call to undefined function inner() $inner(); //PHP Fatal error: Function name must be a string ?>
Вывод:
test test
[Переписано в соответствии с комментарием @PierredeLESPINAY.]
Это не просто побочный эффект, а действительно очень полезная функция для динамического изменения логики вашей программы. Это из процедурных дней PHP, но может пригодиться и с OO-архитектурами, если вы хотите наиболее просто реализовать альтернативные реализации для определенных автономных функций. (В то время как OO – лучший выбор в большинстве случаев, это вариант, а не мандат, а некоторые простые задачи не нуждаются в дополнительном рывке).
Например, если вы динамически / условно загружаете плагины из своей структуры и хотите, чтобы жизнь авторов плагина была очень простой, вы можете предоставить стандартные реализации для некоторых критических функций, которые плагин не переопределил:
<?php // Some framework module function provide_defaults() { // Make sure a critical function exists: if (!function_exists("tedious_plugin_callback")) { function tedious_plugin_callback() { // Complex code no plugin author ever bothers to customize... ;) } } }
Функции, определенные в функциях, которые я не вижу многого, но условно определенные функции я могу. Например:
if ($language == 'en') { function cmp($a, $b) { /* sort by English word order */ } } else if ($language == 'de') { function cmp($a, $b) { /* sort by German word order; yes it's different */ } } // etc
И тогда весь ваш код должен сделать, это использовать функцию «cmp» в таких вещах, как usort (), чтобы вы не мешали языковым проверкам по всему вашему коду. Теперь я этого не сделал, но я могу видеть аргументы для этого.
Весь мой php – OO, но я вижу использование для вложенных функций, особенно когда ваша функция рекурсивна и не обязательно является объектом. То есть, он не вызывается за пределами функции, в которую он вложен, но является рекурсивным и впоследствии должен быть функцией.
Существует мало смысла в создании нового метода для экспресс-использования одного другого метода. Для меня это неуклюжий код и сорт – не суть OO. Если вы никогда не назовете эту функцию нигде, вставьте ее.
В вызове webservice мы находили его гораздо более низкими накладными расходами (память и скорость) динамически, в том числе вложенным способом, отдельные функции по библиотекам, полным 1000 функций. Типичный стек вызовов может составлять от 5 до 10 вызовов, но только для того, чтобы связать дюжину файлов на 1-2 кбайта динамически было лучше, чем включать мегабайты. Это было сделано, просто создав небольшую утилиту, которая требует обертывания. Включенные функции становятся вложенными в функции над стеком вызовов. Рассмотрим это в отличие от классов, полный 100 функций, которые не требовались при каждом вызове webservice, но также могли использовать встроенные функции ленивой загрузки php.
Все сказанное выше, можно просто создать вложенную функцию для замены некоторого локализованного повторяющегося кода внутри функции (который будет использоваться только внутри родительской функции). Некоторые могут сказать, что просто создают частные методы (или меньшие блоки кода), но это замалчивает воды, когда сверхспециальная задача (которая является эксклюзивной для родителя) должна быть модульной, но не обязательно доступна остальной части класса ( или глобальное пространство в процедурной программе). Хорошая новость заключается в том, что, если окажется, что вам нужна эта функция где-то еще, исправление довольно элементарно (переместите определение в более центральное место).
Вообще говоря, использование JavaScript в качестве стандарта для оценки других языков программирования на языке C – это плохая идея. JavaScript, безусловно, является его собственным животным по сравнению с PHP, Python, Perl, C, C ++ и Java. Конечно, есть много общего сходства, но подробные подробные детали (ссылка JavaScript: The Definitive Guide, 6th Edition, главы 1-12 ), когда обращают на это внимание, делают основной JavaScript уникальным, красивым, разным, простым и комплекс все одновременно. Это мои два цента.
Чтобы быть ясным, я не говорю, что вложенные функции являются частными. Именно это вложение может помочь избежать беспорядка, когда нужно что-то тривиальное быть модульным (и требуется только родительской функцией).
Вложенные функции полезны в Memoization (результаты кеширования для повышения производительности).
<?php function foo($arg1, $arg2) { $cacheKey = "foo($arg1, $arg2)"; if (! getCachedValue($cacheKey)) { function _foo($arg1, $arg2) { // whatever return $result; } $result = _foo($arg1, $arg2); setCachedValue($cacheKey, $result); } return getCachedValue($cacheKey); } ?>
Вложенные функции полезны, если вы хотите, чтобы вложенная функция использовала переменную, которая была объявлена в родительской функции.
<?php ParentFunc(); function ParentFunc() { $var = 5; function NestedFunc() { global $var; $var = $var + 5; return $var; }; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; } ?>