为什么 PHP 的 foreach 会(仅)推进其数组的指针一次?

php
2022-08-30 21:15:17

这是一个关于PHP中实现方式背后的原因的好奇心问题。foreach

考虑:

$arr = array(1,2,3);
foreach ($arr as $x) echo current($arr) . PHP_EOL;

这将输出:

2
2
2

我理解将数组指针倒回开头;但是,为什么它只增加一次呢?魔法盒里发生了什么??这只是一个(丑陋的)人工制品吗?foreach


感谢@NickC - 对于其他任何好奇的人,你可以在这里阅读基础知识zvalrefcount


答案 1

在第一次迭代之前,它被“软复制”用于 。这意味着没有实际的复制,只有 zval 的 1 将增加到 。$arrayforeachrefcount$array2

在第一次迭代中:

  1. 该值被提取到 中。$x
  2. 内部数组指针移动到下一个元素,即现在指向 。2
  3. current通过引用传递调用。由于引用PHP不能再与循环共享,它需要分开(“硬拷贝”)。$arrayzval

因此,在接下来的迭代中,zval不再与zval相关。因此,它的数组指针不再被修改,并且始终返回相同的元素。$arrayforeachcurrent

顺便说一句,我已经写了一个关于前期复制行为的小摘要。它可能在上下文中引起人们的兴趣,但它与问题没有直接关系,因为它主要讨论硬拷贝。


答案 2

看看有多有趣,如果我们稍微改变一下代码:

$arr = array(1,2,3);
foreach ($arr as &$x) echo current($arr) . PHP_EOL;

我们得到了这个输出:

2
3

一些有趣的参考:

http://nikic.github.com/2011/11/11/PHP-Internals-When-does-foreach-copy.html

http://blog.golemon.com/2007/01/youre-being-lied-to.html

现在,试试这个:

$arr = array(1,2,3);
foreach ($arr as $x) { $arr2 = $arr; echo current($arr2) . PHP_EOL; }

输出:

2
3
1

这确实很奇怪。

那么这个呢:

$arr = array(1,2,3);
foreach ($arr as $x) { $arr2 = $arr; echo current($arr) . ' / ' . current($arr2) . PHP_EOL; }
echo PHP_EOL;
foreach ($arr as $x) { $arr2 = $arr; echo current($arr2) . ' / ' . current($arr2) . PHP_EOL; }

输出:

2 / 2
2 / 2
2 / 2

2 / 2
3 / 3
1 / 1

似乎发生的事情就像NickC答案中所写的那样,再加上当将数组作为参数传递给函数时,当它通过引用传递时,里面的某些东西确实修改了作为参数传递给它的数组......current


推荐