Javascript闭包与PHP闭包,有什么区别?
JS 中的闭包和 PHP 中的闭包有什么区别?它们的工作方式几乎相同吗?在 PHP 中编写闭包时,有什么需要注意的注意事项吗?
JS 中的闭包和 PHP 中的闭包有什么区别?它们的工作方式几乎相同吗?在 PHP 中编写闭包时,有什么需要注意的注意事项吗?
一个区别是两者如何应对存储执行匿名函数的上下文:
// 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闭包都有一个可用的上下文,这意味着你可以在闭包本身内部使用(尽管弄清楚实际指的是什么通常很复杂) - PHP当前的稳定版本(PHP 5.3)还不支持闭包,但PHP即将推出的版本(PHP 5.4)将支持绑定和重新绑定使用(请参阅对象扩展RFC以获取更多信息。this
this
this
$this
$this
$closure->bind($this)
第三个区别是两种语言如何处理分配给对象属性的闭包:
// 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
我在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/每个循环
非常适合作为参数提供给函数/类
他们令人讨厌的是...
你不能对它们进行类型转换,因为它们只是函数...