Вопрос

В 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, очевидно, будет лучшим выбором :)

Другие советы

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

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

<?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 в качестве стандарта для оценки других языков программирования на основе Си - плохая идея. JavaScript определенно является собственным животным по сравнению с PHP, Python, Perl, C, C ++ и Java. Конечно, есть много общего сходства, но подробности (см. JavaScript: Полное руководство, 6-е издание, главы 1-12 ), когда основное внимание уделяется, делают основной JavaScript уникальным, красивые, разные, простые и сложные одновременно. Это мои два цента.

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

Весь мой php - OO, но я вижу использование для вложенных функций, особенно когда ваша функция рекурсивная и не обязательно является объектом. То есть он не вызывается вне функции, в которую он вложен, но рекурсивен и впоследствии должен быть функцией.

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

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

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

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 (). 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 (), результат будет таким:

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 (), чтобы избежать ошибки повторного объявления

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

Вложенные функции полезны в 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>";
}
?>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top