В 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()
будут запущены. Они также не находятся в частной области видимости; они действительно загрязняют глобальный масштаб, хотя и с задержкой. И в качестве обратного вызова внешний обратный вызов все еще может быть вызван только один раз. Я до сих пор не понимаю, насколько полезно применять его к массиву, который, скорее всего, вызывает псевдоним более одного раза.Единственный пример «реального мира», который я мог выкопать, - это этот , который может запускаться только один раз и может быть переписан более чистым, IMO.
Единственное использование, которое я могу придумать, - это вызов модулями
[name]_include
метода, который устанавливает несколько вложенных методов в глобальном пространстве в сочетании сif (!function_exists ('somefunc')) { function somefunc() { } }
чеки.
ООП PHP, очевидно, был бы лучшим выбором :)
источник
def
объявления в RubyЕсли вы используете 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 ?>
Вывод:
источник
[Переписано в соответствии с комментарием @PierredeLESPINAY.]
Это вообще не просто побочный эффект, а на самом деле очень полезная функция для динамического изменения логики вашей программы. Это из процедурных дней PHP, но может пригодиться и с объектно-ориентированной архитектурой, если вы хотите предоставить альтернативные реализации для определенных автономных функций наиболее простым способом. (Хотя в большинстве случаев объектно-ориентированный подход является лучшим выбором, это вариант, а не поручение, и некоторые простые задачи не требуют лишних хлопот.)
Например, если вы динамически / условно загружаете плагины из своего фреймворка и хотите упростить жизнь авторам плагинов, вы можете предоставить реализации по умолчанию для некоторых критических функций, которые плагин не переопределял:
<?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 (), чтобы вы не засоряли языковые проверки по всему коду. Сейчас я этого не делал, но вижу аргументы в пользу этого.
источник
При всем вышесказанном можно просто создать вложенную функцию для замены некоторого локализованного повторяющегося кода внутри функции (который будет использоваться только внутри родительской функции). Анонимная функция - прекрасный пример этого.
Кто-то может сказать, что просто создайте частные методы (или меньшие блоки кода) в классе, но это запутывает воду, когда сверхспецифическая задача (которая является эксклюзивной для родителя) должна быть модульной, но не обязательно доступной для остальной части класс. Хорошая новость заключается в том, что если окажется, что эта функция вам нужна где-то еще, исправление будет довольно элементарным (переместите определение в более центральное место).
Вообще говоря, использование JavaScript в качестве стандарта для оценки других языков программирования на основе C - плохая идея. JavaScript определенно является самостоятельным животным по сравнению с PHP, Python, Perl, C, C ++ и Java. Конечно, есть много общего, но мелкие мелкие детали (ссылка на JavaScript: The Definitive Guide, 6-е издание, главы 1-12 ), если на них обратить внимание, сделают ядро JavaScript уникальным, красивым, разным, простым и сложны все одновременно. Это мои два цента.
Чтобы быть ясным, я не говорю, что вложенные функции являются частными. Именно такое вложение может помочь избежать беспорядка, когда что-то тривиальное нужно модулировать (а это необходимо только родительской функции).
источник
Весь мой php - объектно ориентированный объект, но я вижу использование вложенных функций, особенно когда ваша функция является рекурсивной и не обязательно является объектом. Другими словами, он не вызывается вне функции, в которую он вложен, но является рекурсивным и, следовательно, должен быть функцией.
Нет смысла создавать новый метод для экспресс-использования одного другого метода. Для меня это неуклюжий код и не суть объектно-ориентированного подхода. Если вы никогда не собираетесь вызывать эту функцию где-либо еще, вложите ее.
источник
При вызове веб-сервисов мы обнаружили гораздо меньшие накладные расходы (память и скорость), динамически включая вложенные функции, отдельные функции над библиотеками, полными тысячей функций. Типичный стек вызовов может составлять от 5 до 10 вызовов в глубину, требуя динамического связывания дюжины файлов размером 1-2 КБ, чем включение мегабайт. Это было сделано просто путем создания небольшой обертки служебной функции. Включенные функции становятся вложенными в функции над стеком вызовов. Рассмотрим это в отличие от классов, полных сотен функций, которые не требовались при каждом вызове веб-службы, но также могли использовать встроенные функции отложенной загрузки php.
источник
если вы используете php 7, посмотрите следующее: эта реализация даст вам четкое представление о вложенной функции. Предположим, у нас есть три функции (too (), boo () и zoo ()), вложенные в функцию foo (). boo () и zoo () имеют одноименную вложенную функцию xoo (). В этом коде я четко закомментировал правила вложенных функций.
function foo(){ echo 'foo() is called'.'<br>'; function too(){ echo 'foo()->too() is called'.'<br>'; } function boo(){ echo 'foo()->boo() is called'.'<br>'; function xoo(){ echo 'foo()->boo()->xoo() is called'.'<br>'; } function moo(){ echo 'foo()->boo()->moo() is called'.'<br>'; } } function zoo(){ echo 'foo()->zoo() is called'.'<br>'; function xoo(){ //same name as used in boo()->xoo(); echo 'zoo()->xoo() is called'.'<br>'; } #we can use same name for nested function more than once #but we can not call more than one of the parent function } } /**************************************************************** * TO CALL A INNER FUNCTION YOU MUST CALL OUTER FUNCTIONS FIRST * ****************************************************************/ #xoo();//error: as we have to declare foo() first as xoo() is nested in foo() function test1(){ echo '<b>test1:</b><br>'; foo(); //call foo() too(); boo(); too(); // we can can a function twice moo(); // moo() can be called as we have already called boo() and foo() xoo(); // xoo() can be called as we have already called boo() and foo() #zoo(); re-declaration error //we cannont call zoo() because we have already called boo() and both of them have same named nested function xoo() } function test2(){ echo '<b>test2:</b><br>'; foo(); //call foo() too(); #moo(); //we can not call moo() as the parent function boo() is not yet called zoo(); xoo(); #boo(); re-declaration error //we cannont call boo() because we have already called zoo() and both of them have same named nested function xoo() }
Теперь, если мы вызовем test1 (), результат будет следующим:
если мы вызовем test2 (), результат будет таким:
Но мы не можем вызывать одновременно text1 () и test2 (), чтобы избежать ошибки повторного объявления.
источник
Я знаю, что это старый пост, но я использую вложенные функции, чтобы дать аккуратный и аккуратный подход к рекурсивному вызову, когда мне нужна только локальная функциональность - например, для создания иерархических объектов и т. Д. (Очевидно, вам нужно быть осторожным, родительская функция только звонил один раз):
function main() { // Some code function addChildren ($parentVar) { // Do something if ($needsGrandChildren) addChildren ($childVar); } addChildren ($mainVar); // This call must be below nested func // Some more code }
Следует отметить, что в php по сравнению с JS, например, вызов вложенной функции должен выполняться после, то есть ниже, объявления функции (по сравнению с JS, где вызов функции может быть где угодно в родительской функции
источник
Я действительно использовал эту характеристику только тогда, когда было полезно выполнить небольшую рекурсивную функцию внутри основной, более категориальной функции, но я не хотел перемещать ее в другой файл, потому что это было фундаментальным для поведения основного процесса. Я понимаю, что есть и другие "лучшие практики" для этого, но я хочу, чтобы мои разработчики видели эту функцию каждый раз, когда смотрят на мой синтаксический анализатор, вероятно, что они все равно должны изменить ...
источник
Вложенные функции полезны в 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); } ?>
источник
_foo()
что приведет к фатальной ошибке.Вложенные функции полезны, если вы хотите, чтобы вложенная функция использовала переменную, объявленную в родительской функции.
<?php ParentFunc(); function ParentFunc() { $var = 5; function NestedFunc() { global $var; $var = $var + 5; return $var; }; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; } ?>
источник