让我在说这句话之前先说我知道它是什么foreach,做什么和如何使用。这个问题关系到它在引擎盖下的工作方式,我不希望出现“这就是如何用foreach” 循环数组”的答案。
很长时间以来,我一直认为该方法foreach可用于数组本身。然后,我发现许多关于它可以与数组副本一起使用的事实的引用,从那时起,我一直以为这是故事的结尾。但是我最近对此事进行了讨论,经过一番试验后发现这实际上并非100%正确。
让我表明我的意思。对于以下测试用例,我们将使用以下数组:
$array = array(1, 2, 3, 4, 5);测试用例1:
foreach ($array as $item) { echo “$item\n”; $array[] = $item;}print_r($array);
/* Output in loop: 1 2 3 4 5 $array after loop: 1 2 3 4 5 1 2 3 4 5 */这清楚地表明,我们不是直接使用源数组-否则循环将永远持续下去,因为在循环过程中我们不断将项目推入数组。但是只是为了确保是这种情况:
测试用例2:
foreach ($array as $key => $item) { $array[$key + 1] = $item + 2; echo “$item\n”;}
print_r($array);
/* Output in loop: 1 2 3 4 5 $array after loop: 1 3 4 5 6 7 */这支持了我们的初始结论,我们在循环期间正在使用源数组的副本,否则将在循环期间看到修改后的值。但…
如果查看手册,则会发现以下语句:
当foreach首先开始执行时,内部数组指针将自动重置为数组的第一个元素。
对…这似乎表明它foreach依赖于源数组的数组指针。但是我们刚刚证明我们不使用源数组,对吗?好吧,不完全是。
测试用例3:
// Move the array pointer on one to make sure it doesn’t affect the loopvar_dump(each($array));
foreach ($array as $item) { echo “$item\n”;}
var_dump(each($array));
/* Output array(4) { [1]=> int(1) [“value”]=> int(1) [0]=> int(0) [“key”]=> int(0) } 1 2 3 4 5 bool(false)*/因此,尽管事实上我们没有直接使用源数组,但我们直接使用了源数组指针-指针在循环末尾位于数组的末尾这一事实表明了这一点。除非这不是真的-如果是这样,那么测试用例1将永远循环。
PHP手册还指出:
由于foreach依赖内部数组指针,因此在循环内更改它可能导致意外行为。
好吧,让我们找出“意外行为”是什么(从技术上讲,任何行为都是意外的,因为我不再知道会发生什么)。
测试用例4:
foreach ($array as $key => $item) { echo “$item\n”; each($array);}
/* Output: 1 2 3 4 5 */测试案例5:
foreach ($array as $key => $item) { echo “$item\n”; reset($array);}
/* Output: 1 2 3 4 5 */…没有什么意外的,实际上似乎支持“源代码复制”理论。
问题
这里发生了什么?我的C-fu不足以让我仅通过查看PHP源代码就能得出正确的结论,如果有人可以将其翻译成英文,我将不胜感激。
在我看来,它foreach可以处理数组的副本,但是在循环之后将源数组的数组指针设置为数组的末尾。
这是正确的故事吗?如果没有,它到底在做什么?是否存在在a期间使用调整数组指针(each(),reset()等)的函数foreach会影响循环结果的情况?