PHP - foreach 因空合并运算符而丢失引用

fei*_*iny 9 php reference null-coalescing-operator

Q1:我认为??在以下情况下将不会执行任何操作:

$a = [1, 2];
foreach ($a ?? [] as &$v) {
    $v++;
}
var_dump($a);
Run Code Online (Sandbox Code Playgroud)

但为什么?

array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}
Run Code Online (Sandbox Code Playgroud)

Q2:这更奇怪:

foreach ($a = [1, 2] as &$v) {
    $v++;
}
var_dump($a);
// output
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}
Run Code Online (Sandbox Code Playgroud)

我的想法:我认为表达式不可引用,但foreach捕获错误或以某种方式然后复制。有效的参考资料:

$a = 1;
$c = &$a;
Run Code Online (Sandbox Code Playgroud)

不工作:

$a = 1;
$c = &($a);
$c = &($a ?? []);
$c = &($a + 1);
Run Code Online (Sandbox Code Playgroud)

??复印吗?我只是不想用 if 为 null 来包装foreachif (isset($a))并且$aforeach失败。

Ja͢*_*͢ck 8

TL;DR对于您的情况,您可以考虑以这种方式使用空合并运算符:

$a = $a ?? [];
foreach ($a as &$v) { ... }
Run Code Online (Sandbox Code Playgroud)

或者,根本不使用引用,通过使用array_map()或 使用键在底层数组中进行修改。

Q1

$a = [1, 2];
foreach ($a ?? [] as &$v) {
    $v++;
}
var_dump($a);
Run Code Online (Sandbox Code Playgroud)

合并运算符使用原始数组的副本,然后应用右侧操作数 if null。因此,迭代发生在原始数组的副本上。

您可以将其与以下内容进行比较:

$a = [1, 2];
$x = $a ?? [];
$x[1] = 4;
var_dump($a); // [1, 2]
Run Code Online (Sandbox Code Playgroud)

代码洞察

compiled vars:  !0 = $a, !1 = $v
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   8     0  E >   ASSIGN                                                   !0, <array>
   9     1        COALESCE                                         ~3      !0
         2        QM_ASSIGN                                        ~3      <array>
         3      > FE_RESET_RW                                      $4      ~3, ->8
... rest of looping code
Run Code Online (Sandbox Code Playgroud)

的第一个操作数FE_RESET_RW是将要迭代的哈希变量,您可以看到它~3而不是!0$a在您的代码中),这正是您期望发生的情况。

Q2

foreach ($a = [1, 2] as &$v) {
    $v++;
}
Run Code Online (Sandbox Code Playgroud)

这里发生的情况是,赋值的返回值$a = [1, 2]被用作要迭代的数组。

您可以将此行为与类似的行为进行比较:

$x = $a = [1, 2];
$x[0] = 4; // modify in-place
var_dump($a); // [1, 2]
Run Code Online (Sandbox Code Playgroud)

代码洞察

$x = $a = [1, 2];
$x[0] = 4; // modify in-place
var_dump($a); // [1, 2]
Run Code Online (Sandbox Code Playgroud)

同样,$2是 的第一个操作数FE_RESET_RW,它是赋值结果,因此迭代不会针对!0($a在您的代码中) 发生。