【问题标题】:Javascript closures vs PHP closures, what's the difference?Javascript 闭包 vs PHP 闭包,有什么区别?
【发布时间】:2011-11-17 01:28:21
【问题描述】:

JS 中的闭包和 PHP 中的闭包有什么区别?它们的工作方式几乎相同吗?在 PHP 中编写闭包时是否有任何注意事项需要注意?

【问题讨论】:

    标签: php javascript closures


    【解决方案1】:

    一个区别是两者如何处理存储执行匿名函数的上下文:

    // JavaScript:
    var a = 1;
    var f = function() {
       console.log(a);
    };
    a = 2;
    f();
    // will echo 2;
    
    // PHP
    $a = 1;
    $f = function() {
        echo $a;
    };
    $a = 2;
    $f();
    // will result in a "PHP Notice:  Undefined variable: a in Untitled.php on line 5"
    

    要修复此通知,您必须使用 use 语法:

    $a = 1;
    $f = function() use ($a) {
        echo $a;
    };
    $a = 2;
    $f();
    // but this will echo 1 instead of 2 (like JavaScript)
    

    要让匿名函数的行为与 JavaScript 对应物一样,您必须使用引用:

    $a = 1;
    $f = function() use (&$a) {
        echo $a;
    };
    $a = 2;
    $f();
    // will echo 2
    

    我认为这是 JavaScript 和 PHP 闭包之间最显着的区别。

    第二个区别是每个 JavaScript 闭包都有一个可用的 this 上下文,这意味着您可以在闭包本身内部使用 this(尽管通常很难弄清楚 @987654328 是什么@ 实际上是指) - PHP 的当前稳定版本 (PHP 5.3) 尚不支持闭包内的 $this,但 PHP 即将推出的版本 (PHP 5.4) 将支持 $this 绑定和使用 $closure->bind($this) 重新绑定(参见 @987654321 @了解更多信息。)

    第三个区别是两种语言如何处理分配给对象属性的闭包:

    // JavaScript
    var a = {
        b: function() {}
    };
    a.b(); // works
    
    
    // PHP
    $a = new stdClass();
    $a->b = function() {};
    $a->b(); // does not work "PHP Fatal error:  Call to undefined method stdClass::b() in Untitled.php on line 4"
    
    $f = $a->b;
    $f(); // works though
    

    如果将闭包分配给类定义中的属性,也是如此:

    class A {
        public $b;
    
        public function __construct() {
            $this->b = function() {};
        }
    
        public function c() {
            $this->b();
        }
    }
    $a = new A();
    // neither
    $a->b();
    // nor
    $a->c();
    // do work
    

    第四个区别: JavaScript 闭包是完全成熟的对象,而在 PHP 中它们是受限对象。例如,PHP 闭包不能拥有自己的属性:

    $fn = function() {};
    $fn->foo = 1;
    // -> Catchable fatal error: Closure object cannot have properties
    

    在 JavaScript 中你可以这样做:

    var fn = function() {};
    fn.foo = 1;
    fn.foo; // 1
    

    第五个区别:返回的闭包可以立即在 Javascript 中调用:

    var fn = function() { return function() { alert('Hi');}}
    fn()();    
    

    不在 PHP 中:

    $fn = function() { return function() { echo('Hi');};};
    $fn()();     // syntax error
    

    【讨论】:

    • 啊,干得好,伙计!我完全忘记了 use 关键字!为你+1!这些天我正在使用 ColdFusion……我没有匿名函数 :(
    • 很好,我现在学到了很多关于闭门器的知识。我也在我的代码中使用了它。很好的答案
    • 在 PHP 上下文中,匿名函数闭包 可以互换使用,尽管有区别。当前的实现甚至使用Closure 作为所有匿名函数的底层类,无论它们是真正的闭包(捕获外部上下文)。 function object 这个词在这个问题上下文中并不重要。
    • +1 那么,您的意思是:PHP 的实现者不知道闭包是什么?是的..我可以相信。
    • @Louis 不。他只是说 PHP 有一个不同的,比 JavaScript 更直观的闭包实现。这并不意味着任何一个实现都是错误的。它们只是不同。
    【解决方案2】:

    我在 PHP 中发现的唯一一件事(非常酷且非常方便!)是能够将它们用作类中的 getter 和 setter,这在以前一直是一场噩梦,JavaScript 也可以在相同的环境中使用方式,但它们的行为与我所看到的几乎相同。

    我不确定两者之间的命名空间约定差异,但正如@Rijk 指出的那样,PHP 网站上有一个专门介绍它们的部分

    <?php 
        class testing {
            private $foo = 'Hello ';
            public $bar  = 'Bar';
    
            #Act like a getter and setter!
            public static $readout = function ($val = null) {
                if (!empty($val)) {
                    testing::$readout = $val;
                }
                return testing::$readout;
            }
        }
    

    它们也非常适合...

    使用控制器循环项目,而不是页面上的新 for/each 循环

    非常适合作为函数/类的参数提供

    他们讨厌的是……

    你不能对它们进行类型转换,因为它们只是函数......

    【讨论】:

    • 为什么要对匿名函数进行类型转换?
    • 如果你有一个函数需要一个数组作为它的参数,一个匿名函数将失败强制尝试,除非我错过了船并且他们将所需的值类型基于函数的最终返回值/输入..
    • 当然,在您的示例中,如果您想将$readout 设置为 null、0、空字符串等,那您就搞砸了。
    【解决方案3】:

    它们的工作方式几乎相同。以下是有关 PHP 实现的更多信息:http://php.net/manual/en/functions.anonymous.php

    您可以使用闭包(在 PHP 中称为“匿名函数”)作为回调:

    // return array of ids
    return array_map( function( $a ) { return $a['item_id']; }, $items_arr );
    

    并将其分配给一个变量:

    $greet = function( $string ) { echo 'Hello ' . $string; }; // note the ; !
    echo $greet('Rijk'); // "Hello Rijk"
    

    此外,匿名函数“继承”定义它们的范围 - 就像 JS 实现一样,有一个陷阱:您必须在 use() 中列出您想要继承的所有变量:

    function normalFunction( $parameter ) {
        $anonymous = function() use( $parameter ) { /* ... */ };
    }
    

    如果你想修改原始变量作为参考。

    function normalFunction( $parameter ) {
        $anonymous = function() use( &$parameter ) { $parameter ++ };
        $anonymous();
        $parameter; // will be + 1
    }
    

    【讨论】:

    • 你必须“相当多地”延伸才能真正说它们以相同的方式工作:)
    • 称我为盲人,但我看不出有什么不同:)
    • 我支持 Rijk,从我所见和使用的情况来看,我没有看到任何可衡量的差异..
    猜你喜欢
    • 1970-01-01
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 2011-07-27
    • 2015-04-25
    • 2011-03-23
    • 2020-04-29
    相关资源
    最近更新 更多