什么是PHP嵌套函数?

问题描述 投票:73回答:12

在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()
php nested-function
12个回答
85
投票

有没有基本上,我一直这样对待作为解析器的副作用。

伊兰加尔佩林是错误的,这些功能在某种程度上私人的,他们根本未申报,直到outer()运行。他们也不能私自范围的,他们做polute全球范围虽然延迟。而作为一个回调外回调可能仍然只能被调用一次。我还没有看到如何有帮助的应用它这很可能要求别名不止一次阵列上。

唯一的“现实世界”的例子,我能挖出个是this只能运行一次,并且可以清洁IMO改写。

我能想到的唯一用途是用于模块调用它设置在全局空间联合多个嵌套方法[名] _include方法

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

检查。

PHP的面向对象显然是一个更好的选择:)


0
投票

我只真正使用这一特性时,它是执行主,多个分类函数里面的小递归函数是有用的,但不想将其移动到不同的文件,因为它是一个初级过程的行为根本。我知道有这样做的另一个“最佳实践”的方式,但我想确保我的开发者看到函数每次看我的解析器的时候,很可能他们无论如何都应该修改什么?


-1
投票

嵌套函数在记忆化(缓存功能的结果来提高性能)是有用的。

<?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);
}
?>

-1
投票

如果你想嵌套函数利用这是父函数内声明的变量嵌套函数是有用的。

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

82
投票

如果你正在使用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

9
投票

[根据@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... ;)
        }
    }
}

7
投票

函数中定义的功能也看不出多大用处的,但是有条件地定义的功能,我可以。例如:

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

然后所有的代码需要做的是使用之类的东西usort的“CMP”()的函数调用,所以你不要乱扔垃圾语言检查在你的代码。现在,我没有这样做,但我可以看到参数做这件事。


3
投票

所有上述虽这么说,一个可能只需创建一个嵌套函数的函数内更换一些局部的,重复的代码(即只会父函数内使用)。一位不愿具名的功能就是一个很好的例子。

也许有人会说,只需要创建一个类私有方法(或更小的代码块),但被弄脏的水域时超特定的任务(也就是排他性父)需要被模块化,但不一定适用于其他地区一类。好消息是,如果事实证明你确实需要该功能在其他地方,该修补程序是相当基本的(移动定义到一个更中心的位置)。

一般来说,使用JavaScript作为标准由评估其他基于C编程语言是一个坏主意。相较于PHP,Python和Perl中,C,C ++和Java JavaScript时,绝对是自己的动物。当然,也有很多相似之处一般,但基本事实,坚韧不拔的细节(参考JavaScript的权威指南,第6版,章节1-12),关注的时候,使核心JavaScript独特,美观,不同的,简单,复杂都在同一时间。这是我的两分钱。

只是要清楚,我不是说嵌套函数是私有的。只是,嵌套可以帮助避免混乱时,模块化一些小事需要(仅被父功能需要)。


2
投票

所有我的PHP的是面向对象的,但我确实看到了使用了嵌套函数,特别是当你的函数是递归的,而不一定对象。也就是说,它不会把它叫做嵌套在功能之外,但是是递归的,并且需要将是一个函数。

有在做一个新的方法快车使用单一的其他方法的小点。对我来说,这是拙劣的代码和排序的不是面向对象的点。如果你永远也不会调用该函数在其他地方,窝了。


1
投票

在Web服务调用,我们发现这是一个非常低的开销(内存和速度),动态,包括以嵌套的方式,在整个的功能1000库各项功能。典型的调用堆栈可能是5-10通话深只需要连接十几1-2kb文件之间的动态比,包括兆更好。这是刚刚通过创建一个小util的功能包装需要做。所包含的功能成为嵌套调用堆栈上方的功能之内。认为这是在对比班满了未在每一个Web服务调用必需的,但也可能使用PHP的内置延迟加载功能的功能100S的。


0
投票

我知道这是一个老的文章,但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相比,其中的函数调用可以在父功能内的任何地方的呼叫到嵌套函数


0
投票

如果你是在PHP 7然后看到这一点:此实现将为您讲述嵌套功能清晰的概念。假设我们有三个功能(太(),BOO()和动物园())嵌套函数foo()。 BOO()和动物园()具有相同的命名嵌套函数水稻白叶枯病菌()。现在,在这个代码中,我已经清楚地注释掉的嵌套函数的规则。

   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(),以避免重新申报错误