Для чего нужны вложенные функции 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()

Ответ 1

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

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

Единственным примером "реального мира", который я мог бы выкопать, является this, который может запускаться только один раз и может быть переписан более чистым IMO.

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

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

проверки.

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

Ответ 2

Если вы используете 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

Ответ 3

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

Ответ 4

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

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 different */ }
} // etc

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

Ответ 9

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

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