我的代码如下:
$app->add(function($req, $res, $next) {
# closure A
$res->on('end', function($res) use ($req) {
# closure B
});
$next();
});
正如你所看到的,我在一个闭包中有一个闭包。关闭B正在从事件中接收$res
ponse,因此它没有问题。但它也是use
$req
来自封闭A.
在这里,我对use
'变量的范围有疑问,我看到两种可能性:
$res->on
的每个新侦听器重新创建了闭包B.因此,有许多闭包B,它们自己的范围从闭包A的已使用变量继承一次。$req
和$res
(正常行为......)但也会替换先前创建的闭包所使用的$req
。如果在请求#2到达之前没有回答请求#1(这是基于事件循环的异步代码),那将会有问题。我希望我足够清楚。我问这个是因为,例如,在JavaScript中,我们有时必须使用回调生成器来确保不替换子闭包的范围。
编辑:我尝试使用一个理论上做同样事情的代码,但更容易测试:
$a = function($var) {
return function() use ($var) {
var_dump($var);
};
};
$fn1 = $a((object) ['val' => 1]);
$fn2 = $a((object) ['val' => 2]);
$fn2();
$fn1();
输出(2,1)显示第一个函数$fn1
保持其原始范围。另外,我注意到Closure对象上var_dump
的输出显示了它带来的范围:
object(Closure)#3 (1) {
["static"]=>
array(1) {
["res"]=>
object(stdClass)#2 (1) {
["val"]=>
int(1)
}
}
}
技术说明?我认为这是因为PHP中的闭包是常规PHP对象,其中use
是一种构造函数。
我是对的吗?任何PHP专家?
答案 0 :(得分:4)
在PHP内部,PHP中的每个Closure
对象都包含一个哈希表。此表存储使用use
关键字复制到闭包范围内的值。 PHP中的数组也使用哈希表实现。
当你在一个闭包中use
一组变量时,就好像你已经创建了一个包含正在使用的每个变量的数组。每个闭包包含它自己独特的"数组"在创建时初始化的值。与普通数组不同,闭包中使用的变量表不能修改。
$var1 = 1;
$var2 = 2;
$closure = function () use ($var1, $var2) {
return $var1 . ", " . $var2 . "\n";
};
$array = [$var1, $var2];
$var1 = 3;
$var2 = 4;
echo $closure(); // echoes 1, 2
echo $array[0] . ", " . $array[1] . "\n"; // echoes 1, 2
更改$var1
的值不会影响$array[0]
的值,也不会更改$var1
中$closure
的值。
当您在闭包中使用对象时,该对象可能会在闭包之外更改,并且这些更改将反映在闭包中。在闭包中使用时不会克隆对象。但是,由于您无法修改变量本身,因此无法将变量更改为指向其他对象。
变量也可以通过引用用于闭包。这允许在闭包之外修改变量值,并且这些变化将在闭包本身内反映出来。
$var1 = 1;
$var2 = 2;
$closure = function () use (&$var1, $var2) {
return $var1 . ", " . $var2 . "\n";
};
$array = [&$var1, $var2];
$var1 = 3;
$var2 = 4;
echo $closure(); // echoes 3, 2
echo $array[0] . ", " . $array[1] . "\n"; // echoes 3, 2
创建上面的闭包时,会在闭包的值表中创建对$var1
的引用,但只会将$var2
的值复制到表中。当$var1
和$var2
的值发生更改时,只会在闭包内更改$var1
的值,因为只有该变量被引用使用。这又类似于创建一个数组,其中$var1
通过引用添加到数组中,但$var2
的值被复制到数组中。
当在闭包内创建闭包时,内部闭包在创建闭包时复制变量的值。它在另一个闭包中创建并不重要。
$value = 1;
$closure = function ($arg) use ($value) {
return function () use ($arg, $value) {
return $value + $arg;
};
};
$value = 10;
$callback1 = $closure(1);
$callback2 = $closure(2);
echo $callback1() . "\n"; // Echoes 2
echo $callback2() . "\n"; // Echoes 3
TL; DR:创建闭包时,变量的值被复制到闭包中。为了能够修改闭包之外的值,必须通过引用使用该值(例如,function () use (&$value) { ... }
)。