Javascript关闭与PHP关闭,有什么区别?

时间:2011-09-14 13:49:57

标签: php javascript closures

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

3 个答案:

答案 0 :(得分:115)

一个不同之处在于如何同时存储执行匿名函数的上下文:

// 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(虽然它通常很复杂)了解this实际引用的内容) - PHP的当前稳定版本(PHP 5.3)尚未在闭包内支持$this,但PHP即将推出的版本(PHP 5.4)将支持$this绑定和使用$closure->bind($this)重新绑定(有关详细信息,请参阅Object Extension RFC。)

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

// 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 Closures不能拥有自己的属性:

$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

答案 1 :(得分:4)

我在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循环

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

对他们感到烦恼的是......

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

答案 2 :(得分:2)

他们几乎以同样的方式工作。以下是有关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实现一样,有一个问题:你必须列出你想要在{{1}中继承的所有变量}}:

use()

如果你想修改orignal变量,作为参考。

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