Для чего нужны вложенные функции PHP?



в 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()
314   11  

11 ответов:

в принципе нет, я всегда рассматривал это как побочный эффект парсера.

Эран Гальперин ошибается, что эти функции как-то приватны, они просто необъявленные пока 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, если вы хотите предоставить альтернативные реализации для некоторых автономных функций самым простым способом. (В то время как ОО является лучшим выбором большинства время, это вариант, а не мандат, и некоторые простые задачи не нуждаются в дополнительной крафт.)

например, если вы динамически / условно загружаете плагины из своей платформы и хотите сделать жизнь авторов плагинов очень простой, вы можете предоставить реализации по умолчанию для некоторых критических функций, которые плагин не переопределял:

<?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, но я вижу использование вложенных функций, особенно когда ваша функция рекурсивна и не обязательно является объектом. То есть, он не вызывается вне функции, в которую он вложен, но является рекурсивным и впоследствии должен быть функцией.

нет никакого смысла в создании нового метода для экспресс-использования одного другого метода. Для меня это неуклюжий код и вроде бы не смысл ОО. Если вы не собираетесь вызывать эту функцию в любом другом месте, гнездо его.

все вышесказанное, можно просто создать вложенную функцию для замены некоторого локализованного, повторяющегося кода внутри функции (который будет использоваться только внутри родительской функции). Анонимная функция является прекрасным примером этого.

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

вообще говоря, использование JavaScript в качестве стандарта для оценки других языков программирования на основе C-это плохая идея. JavaScript определенно является своим собственным животным по сравнению с PHP, Python, Perl, C, C++ и Java. Конечно, есть много общего сходства, но мелкие, песчаные детали (ссылка JavaScript: окончательное руководство, 6-е издание, главы 1-12), когда на него обращают внимание, делают ядро JavaScript уникальным, красивым, разным, простым и сложным одновременно. Это мои два цента.

просто чтобы быть ясно, я не говорю, что вложенные функции являются частными. Только это вложение может помочь избежать беспорядка, когда что-то тривиальное должно быть модулировано (и требуется только родительской функцией).

в вызове webservice мы обнаружили, что он намного меньше накладных расходов (памяти и скорости) динамически, включая вложенные функции, отдельные функции над библиотеками, полными 1000 функций. Типичный стек вызовов может быть между 5-10 глубокими вызовами, требующими только динамического связывания дюжины файлов 1-2kb, лучше, чем включение мегабайт. Это было сделано просто путем создания небольшой функции util требуется обертывание. Включенные функции становятся вложенными в функции над стеком вызовов. Рассмотрим это в отличие от классов, полных 100s функций, которые не требовались при каждом вызове webservice, но также могли использовать встроенные функции ленивой загрузки php.

вложенные функции полезны в 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>";
}
?>

Я знаю, что это старый пост, но fwiw я использую вложенные функции, чтобы дать аккуратный и аккуратный подход к рекурсивному вызову, когда мне нужна только локальная функциональность-например, для построения иерархических объектов и т. д. (Очевидно, вам нужно быть осторожным, родительская функция вызывается только один раз):

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, где вызов функции может быть в любом месте родительской функции

если вы находитесь в php 7, то смотрите это: Эта реализация даст вам четкое представление о вложенной функции. Предположим, что у нас есть три функции(too (), boo() и zoo ()), вложенные в функцию foo(). БУ() и зоопарк() у одноименного вложенную функцию Результаты поиска(). Теперь в этом коде я четко прокомментировал правила вложенных функций.

   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 () выход будет такой:

test1:
foo() is called
foo()->too() is called
foo()->boo() is called
foo()->too() is called
foo()->boo()->moo() is called
foo()->boo()->xoo() is called

если мы вызовем test2 () выход будет это:

test2:
foo() is called
foo()->too() is called
foo()->zoo() is called
zoo()->xoo() is called

но мы не можем вызвать оба text1 () и test2 () одновременно, чтобы избежать ошибки повторного объявления

Comments

    Ничего не найдено.