【问题标题】:Scope of variables with a function within a function?函数内函数的变量范围?
【发布时间】:2012-06-06 19:20:39
【问题描述】:

在 Python 中,您可以拥有以下内容:

def foo(param1, param2):
    def bar():
        print param1 + param2
    bar()

虽然我在 PHP 中遇到了这种行为的一些困难。 我希望这可以通过以下方式工作:

function foo($param1, $param2)
{
    function bar()
    {
        echo $param1 + $param2;
    }
    bar();
}

但这失败了。所以我读了一些关于闭包的文章(这不是叫做闭包吗?我知道它是用 Python 编写的)。在php documentation 中关于匿名函数(他们说这些函数被实现为闭包),他们告诉您以下列方式使用 use() 表达式:

function foo($param1, $param2)
{
    function bar() use($param1, $param2)
    {
        echo $param1 + $param2;
    }
    bar();
}

但这仍然失败。所以我把它改成了 PHP 匿名函数,就像这样:

function foo($param1, $param2)
{
    $bar = function() use($param1, $param2)
    {
        echo $param1 + $param2;
    };
    $bar();
}

这确实有效,但它看起来真的很难看。我错过了什么吗?我可以以任何方式改善这一点吗?还是我只需要使用“丑陋”的方式?

(我不是在寻找关于闭包是否有用的讨论)

【问题讨论】:

    标签: php closures anonymous-function


    【解决方案1】:

    我在您链接到的手册页上找不到function bar() use($param1, $param2) 语法,只有“丑陋”的有效版本(真正匿名)。我想你必须使用它。

    在您的第二个示例中,bar 不是闭包。要在 PHP 中创建闭包,您必须使用丑陋的 useClosure class。每个函数都会创建自己的局部作用域,但闭包不是自动的。

    PHP 似乎对术语“闭包”有一个奇怪的定义,正如您在阅读manual 时可能注意到的那样。他们将其定义为“匿名函数”的同义词:

    匿名函数,也称为闭包 (...)

    令人困惑,对吧?后来,他们解释说如果你想继承父作用域,你需要 use 关键字:

    闭包也可以从父作用域继承变量。任何此类变量都必须在函数头中声明。

    PHP Wiki rfc page on closures 给了我们一些关于为什么以这种方式实现闭包的提示:

    PHP 的范围概念与其他语言定义的范围概念完全不同。将此与变量变量($$var)结合起来,很明显,自动检测外部范围内引用了哪些变量是闭包是不可能的。此外,由于默认情况下全局变量在函数内部都不可见,因此自动使父作用域可用将与 PHP 遵循的当前语言概念相违背。

    【讨论】:

    • 我也找不到该语法,我只是假设一周前在寻找解决方案时文档页面中缺少它:-)
    • 问题是,该页面是关于匿名函数的,但该函数不是匿名的,它有一个名称 (bar)。
    • 是的,我知道这是关于匿名函数的,但在我的词汇表中,闭包是另一个函数/方法中的函数/方法。搜索 PHP 闭包只会将该页面列为关于闭包的有效页面。事件 PHP 声明它们的匿名函数是由闭包构成的。
    • @您的编辑,确实令人困惑。有函数/方法、匿名函数、闭包和 lambda。但它们都“应该”不同。在我的编程词汇中。
    • @Daan 我完全同意。但这不应该让我们感到惊讶,因为它是 PHP(叹气)。
    【解决方案2】:

    在 PHP 中,您不能访问中间作用域。您只有本地范围和全局范围。这是 PHP 不正当的作用域规则的产物,与任何理智的语言的作用域规则完全相反。

    【讨论】:

    • 所以我坚持使用后一种解决方案?
    【解决方案3】:

    在 PHP 中,命名函数声明 (function bar ()) 在全局范围内声明一个函数。因此,在您的第一个示例中,当您运行 foo 函数时,它将在全局范围内定义一个 bar 函数,然后 每个人 都可以访问 bar 函数,就像您声明它一样在foo 之外。 PHP 中的函数和变量是分开的。命名函数只有一个作用域:全局;虽然你有局部变量,但没有局部范围的函数这样的东西。

    换句话说,把它放在foo 里面是一种错觉;命名函数声明总是全局声明它;将它放在foo 中只会延迟声明运行的时间(因此延迟定义它的时间)到foo 的执行。

    你需要一个闭包。其他答案已向您展示了如何做到这一点。

    【讨论】:

    • 该死的!我在想我在使用闭包时没有污染全局命名空间!每天学习新东西,感谢您提供的信息!
    • @DaanTimmer:使用闭包时不会污染全局命名空间。但是bar 不是闭包(它不能关闭局部变量,正如您发现的那样)。 PHP 中只有匿名函数是闭包。
    • 我仍然称第一个栏为闭包 :P 但这就是我所知道的。但确实如此。第一家酒吧的正式名称是什么?有什么线索吗?
    • @DaanTimmer:我会说,嵌套函数
    猜你喜欢
    • 1970-01-01
    • 2012-10-04
    • 2016-10-26
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多