其他闭包中的PHP闭包:范围为;使用「;

其他闭包中的PHP闭包:范围为;使用「;,php,closures,Php,Closures,我有一个如下代码: $app->add(function($req, $res, $next) { # closure A $res->on('end', function($res) use ($req) { # closure B }); $next(); }); 正如你所看到的,我有一个闭包中的闭包。闭包B正在从事件接收$response,因此没有问题。但它也是闭包A中的useing$request。 在这里,我对use'd变量

我有一个如下代码:

$app->add(function($req, $res, $next) {
    # closure A
    $res->on('end', function($res) use ($req) {
        # closure B
    });
    $next();
});
正如你所看到的,我有一个闭包中的闭包。闭包B正在从事件接收
$res
ponse,因此没有问题。但它也是闭包A中的
use
ing
$req
uest。 在这里,我对
use
'd变量的范围表示怀疑,我看到了两种可能性:

  • 任何响应都将有自己的请求对象,因为闭包B是为传递给
    $res->on
    的每个新侦听器重新创建的。所以有很多闭包B,它们自己的作用域从闭包A的使用变量继承一次
  • 或者:任何新请求都将替换闭包A中的
    $req
    $res
    (正常行为…),但也将替换先前创建的闭包B使用的
    $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
保持了其原始范围。另外,我注意到闭包对象上的
var\u dump
输出显示了它带来的范围:

object(Closure)#3 (1) {
  ["static"]=>
  array(1) {
    ["res"]=>
    object(stdClass)#2 (1) {
      ["val"]=>
      int(1)
    }
  }
}
技术解释?我认为这是因为PHP中的闭包是常规PHP对象,
use
是一种构造函数

  • 上面示例中的闭包的作用如下:
  • 但不是这样,我强制PHP保持相同的引用,这在闭包的“构造函数”中是不可能的:

我说得对吗?任何PHP专家?

在PHP内部,每个
闭包
对象都包含一个哈希表。此表存储使用
use
关键字复制到闭包范围中的值。PHP中的数组也使用哈希表实现

当您
在闭包中使用一组变量时,就好像您创建了一个包含所使用的每个变量的数组。每个闭包都包含自己独特的值“数组”,这些值在创建闭包时被初始化。与普通数组不同,闭包中使用的变量表不能修改

$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]
处的值,也不会更改
$closure
$var1
的值

在闭包中使用对象时,该对象可能会在闭包外部更改,这些更改将反映在闭包中。对象在闭包中使用时不会被克隆。但是,由于无法修改变量本身,因此无法将变量更改为指向其他对象

变量也可以通过引用在闭包中使用。这允许在闭包外部修改变量值,并在闭包内部反映这些更改

$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){…}
)。

我不知道为什么我从来没有接受过这个答案,但它在当时对理解PHP的内部结构有很大帮助。谢谢=)