it-swarm.com.ru

Что 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()
72
meouw

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

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

Единственный пример из «реального мира», который я мог выкопать, это это , который может быть запущен только один раз и может быть переписан для более чистого ИМО.

Единственное использование, о котором я могу думать, - это чтобы модули вызывали метод [name] _include, который устанавливает несколько вложенных методов в глобальном пространстве в сочетании с 

if (!function_exists ('somefunc')) {
  function somefunc() { }
}

чеки.

PHP OOP, очевидно, будет лучшим выбором :)

80
Martijn Laarman

Если вы используете PHP 5.3, вы можете получить более похожее на Javascript поведение с анонимной функцией:

<?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
78
user641463

[Переписано в соответствии с комментарием @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... ;)
        }
    }
}
9
Sz.

Функции, определенные внутри функций, я не вижу особой пользы, но условно определенные функции я могу. Например:

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 (), чтобы вы не засоряли проверки языка во всем коде. Сейчас я этого не сделал, но вижу аргументы для этого.

6
cletus

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

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

2
Jesse James Richard

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

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

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

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

2
Anthony Rutledge

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

1
ZhuLien

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

0
Prince Billy Graham

Вложенные функции полезны, если вы хотите, чтобы вложенная функция использовала переменную, которая была объявлена ​​в родительской функции.

<?php
ParentFunc();
function ParentFunc()
{
  $var = 5;
  function NestedFunc()
  {
    global $var;
    $var = $var + 5;
    return $var;
  };
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
}
?>
0
Matthew

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

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

0
user8333817

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

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

0
MJHd