PHP的foreach()如何在单个数组上成功嵌套?

How can PHP's foreach() be successfully nested on a single array?

考虑以下代码:

$a = [1, 2, 3];

foreach ($a as $x) {
    foreach ($a as $y) {
        echo "$x $y\n";
    }
}

正如人们所期望的那样,它给出了以下结果:

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3

虽然对结果很满意,但我很惊讶它的工作原理,因为根据 manual,它依赖于数组的内部指针:

When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.

As foreach relies on the internal array pointer, changing it within the loop may lead to unexpected behavior.

所以我们可以预期在第一个内部使用嵌套的 foreach 会共享相同的内部指针,并产生以下结果:

1 1
1 2
1 3

因为第一个foreach会看到嵌套foreach留下的内部指针的状态。

我可以想到两种可能的实际行为解释:

就我的文化而言,这在内部是如何运作的?

简答。 PHP确实在这种情况下复制了数组(即数组结构)。 Foreach 可以在各种情况下这样做,以防止出现此类问题。有些人认为 foreach always 复制数组,但事实并非如此(那样效率低下)。

我找到了一篇很棒的博客 post,它更详细地描述了这种行为:

PHP internals: When does foreach copy?

总结:

  • foreach 将复制数组 structure 当且仅当迭代 数组未被引用且引用计数 > 1
  • foreach 会 另外复制数组 values 当且仅当前一点 应用并通过引用完成迭代