其他闭包中的 PHP 闭包 : scope of "use"

标签 php closures

我有一个看起来像这样的代码:

$app->add(function($req, $res, $next) {
    # closure A
    $res->on('end', function($res) use ($req) {
        # closure B
    });
    $next();
});

如您所见,我有一个闭包中的闭包。闭包 B 正在接收来自事件的 $response,因此没有问题。但它也 useing $req来自闭包 A 的请求。 在这里,我对 use 变量的范围有疑问,我看到两种可能性:

  • 任何响应都会有自己的请求对象,因为闭包 B 是为传递给 $res->on 的每个新监听器重新创建的。所以有很多闭包 B,它们自己的作用域从闭包 A 的使用变量中继承一次。
  • 或者:任何新请求都将替换闭包 A 中的 $req$res(正常行为...),但也会替换 $req 由先前创建的闭包 B 使用。如果在请求 #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 专家?

最佳答案

在内部,PHP 中的每个Closure 对象都包含一个哈希表。此表存储使用 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]的值,也不会改变$var1的值> 在 $closure 中。

当您在闭包中使用对象时,该对象可能会在闭包之外发生更改,并且这些更改将反射(reflect)在闭包中。在闭包中使用时不会克隆对象。但是,因为您无法修改变量本身,所以您无法更改变量以指向不同的对象。

变量也可以通过引用在闭包中使用。这允许在闭包之外修改变量值,并且这些更改会反射(reflect)在闭包本身内。

$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 闭包 : scope of "use",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31316381/

相关文章:

php - 监控 Telegram channel 通过机器人加入和离开

php - .htaccess - 将站点从 .html 移动到 .php,但排除一个文件夹

Javascript 函数不返回 AngularJS 中保存的值

javascript - 递归中的闭包

javascript - 从其他页面调用时在 PHP 中调试 MySQL 查询

php - 如何测试Flash动画是否在PHP中播放声音?

php - Codeigniter 使用什么设计模式?

arrays - 如何创建一组未装箱的函数/闭包?

javascript 闭包仍然适用

java - BGGA 闭包作为 java 的附加解决方案?