什么是PHP嵌套函数?

时间:2009-01-06 09:56:51

标签: php nested-function

在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()

13 个答案:

答案 0 :(得分:81)

基本上没有,我一直认为这是解析器的副作用。

Eran Galperin错误地认为这些函数在某种程度上是私有的,在outer()运行之前它们只是未声明。它们也不是私人范围的,它们确实在全球范围内进行了调查,尽管延迟了。作为回调,外部回调仍然只能被调用一次。我仍然没有看到如何将它应用于一个很可能多次调用别名的数组。

我可以挖掘的唯一'真实世界'示例是this,它只能运行一次,可以重写为更清洁的IMO。

我能想到的唯一用途是模块调用[name] _include方法,该方法在全局空间中设置几个嵌套方法并结合

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

检查。

PHP的OOP显然是更好的选择:)

答案 1 :(得分:80)

如果您使用的是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

答案 2 :(得分:9)

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

答案 3 :(得分:6)

在函数中定义的函数我看不到有用但有条件定义的函数我可以。例如:

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'函数,这样你就不会在代码中乱丢语言。现在我还没有这样做,但我可以看到这样做的论据。

答案 4 :(得分:2)

我的所有php都是OO,但我确实看到了嵌套函数的用法,特别是当你的函数是递归的而不一定是对象时。也就是说,它不会在嵌套的函数之外调用,而是递归的,随后需要成为函数。

为明确使用单一其他方法制作新方法毫无意义。对我来说,这是笨拙的代码,并不是OO的重点。如果您永远不会在其他地方调用该函数,请将其嵌套。

答案 5 :(得分:2)

以上所述,人们可能只是简单地创建一个嵌套函数来替换函数中的一些本地化重复代码(只能在父函数中使用)。匿名函数就是一个很好的例子。

有些人可能会说只是在一个类中创建私有方法(或更小的代码块),但是当一个超特定的任务(父母独有的)需要模块化时,这会混淆水域,但不一定可用于其余的课程。好消息是如果事实证明你确实需要在其他地方使用该功能,那么修复就相当基本(将定义移到更中心的位置)。

一般来说,使用JavaScript作为评估其他基于C语言的编程语言的标准是一个坏主意。与PHP,Python,Perl,C,C ++和Java相比,JavaScript绝对是它自己的动物。当然,有很多一般的相似之处,但是细节,细节(参考 JavaScript:The Definitive Guide,第6版,第1-12章),在注意时,使核心JavaScript独一无二,所有这些都是美丽的,不同的,简单的,复杂的。那是我的两分钱。

为了清楚起见,我并不是说嵌套函数是私有的。只有当一些微不足道的事情需要模块化时(这只是父函数需要),嵌套可以帮助避免混乱。

答案 6 :(得分:1)

在webservice调用中,我们发现它的开销(内存和速度)低得多,包括嵌套方式,单个函数超过1000个函数的库。典型的调用堆栈可能在5-10个调用深度之间,只需要动态链接十几个1-2kb文件,这比包括兆字节更好。这只是通过创建一个小的util函数包装需要来完成的。包含的函数嵌套在调用堆栈上方的函数中。与每个webservice调用不需要的100个函数的类相比,它也可以使用php的内置延迟加载功能。

答案 7 :(得分:0)

嵌套函数在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);
}
?>

答案 8 :(得分:0)

如果希望嵌套函数使用在父函数中声明的变量,嵌套函数很有用。

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

答案 9 :(得分:0)

我知道这是一个老帖子,但是当我只需要本地功能时,我使用嵌套函数给递归调用一个干净整洁的方法 - 例如用于构建分层对象等(显然你需要小心,父函数只被调用一次):

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相比,函数调用可以在父函数中的任何位置< / p>

答案 10 :(得分:0)

如果您使用的是php 7,请参见以下内容: 该实现将为您提供有关嵌套函数的清晰思路。 假设我们在函数foo()中嵌套了三个函数(too(),boo()和zoo())。 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()以避免重新声明错误

答案 11 :(得分:0)

当在主要的,更分类的函数中执行小的递归函数很有用,但又不想将其移至其他文件时,因为它是主要行为的基础,因此我才真正使用此特性处理。我意识到还有其他“最佳实践”方法可以做到这一点,但我想确保我的开发人员每次查看我的解析器时都能看到该功能,很可能他们仍然应该修改这些内容...

答案 12 :(得分:0)

对于那些暗示没有实际使用嵌套函数的人。是的,他们已经使用了,这是一个例子。

想象一下,我有一个名为 my_file.php 的文件,用于从中获取 ajax 结果。但是,如果有时您不想通过 ajax 获得结果,但又想在同一个页面中包含两次而不发生冲突怎么办?

让我们说 ajax 文件 my_file.php :

<?php
// my_file.php used for ajax

$ajax_json_in = 10; 

function calculations($a, $b)
{   $result = $a + $b;
    return $result;
}

$new_result = $ajax_json_in * calculations(1, 2);

$ajax_json_out =  $new_result; 
   
?>

下面的示例包含两次上述文件而没有冲突。您可能不想 ajax 调用它,因为有些情况下您需要将它直接包含在 HTML 中。

<?php
// include the above file my_file.php instead of ajaxing it

function result1 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out; 
}


function result2 
{
    $ajax_json_in = 20; 
    include("my_file.php");
    return $ajax_json_out;
}

?>

包含文件会使文件的函数嵌套。该文件用于 ajax 调用和内联包含!!!

所以嵌套函数在现实生活中是有用的。

祝你有美好的一天。

相关问题