PHP 5 与 PHP 7 关于 foreach 疑问?

PHP手册5.X升级7.0写到:

foreach 通过值遍历时,操作的值为数组的副本
当默认使用通过值遍历数组时,foreach 实际操作的是数组的迭代副本,而非数组本身。这就意味着,foreach 中的操作不会修改原数组的值。

我以为PHP 5 中 foreach 直接操作数组, 而不是复制数组, foreach操作数组副本, 为了验证这个, 我测试一下代码:

$arr = [1, 2, 3];
foreach ($arr as $v) {
    unset($arr[2]);
    var_dump($v);
}
var_dump($arr);

结果跟我想的不一样, 打印出来的结果, 为
代码结果
PHP 7 与 PHP 5结果一样, 我不明白的是如果结果是一样的, 为何升级手册上会写这个? 谷歌查询一下, 在一篇文章中解释手册这个手册这段话, 写几行代码:

$array = [0, 1, 2];
$ref =& $array; // Necessary to trigger the old behavior
foreach ($array as $val) {
    var_dump($val);
    unset($array[1]);
}
var_dump($array);

其结果又跟我想的不一样, 以为都打印出 0, 2.
打印结果2
越想越糊涂, PHP5 操作的是数组本身还是数组复制, 在sf.gg上有一篇文章"当我们使用foreach时,内部究竟发生了什么(PHP5)" 写到:

其实foreach遍历过程中,并不是直接操作$arr(原数组)的,而是会将$arr复制出一个$arrcopy(是一个$arr的一个复制品,我这里以$arrcopy代替),foreach在遍历过程中操作的其实一直是$arrcopy。

越看越觉得奇怪, 又在stackoverflow 看到有关于我类似的问题, 英文能力不行, 勉强靠翻译看了一些, 提及到底层相关知识, 太深奥了. 还是不懂, PHP 5 如果是操作数组副本的话, 应该会跟PHP 7 结果一样, 但是数组前面加了引用, 其结果也不同了. 而且手册上不会写这个段话的

WytheHuang
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 5
DianWang

unset是销毁数组的元素,当你使用unset($arr[key])这种形式时,不论在foreach内还是foreach外,都是对$arr本身的操作,foreach遍历后的$val,才是数组元素的复制,你对它的任何操作,都不会影响到原来的数组。

5年前 评论
WytheHuang

@DianWang 感谢你的回答, 按照你回答, 我是这么理解的, 既然不受影响. 那么$ref = &array 这行代码, PHP 7 应该跟 PHP 5输出结果一样的.

5年前 评论
DianWang

@WytheHuang 探究的精神很好啊,这个你可以在foreach里面用next()看看遍历时指针是否发生了移动,在手册中数组指针那部分有解释

5年前 评论
WytheHuang

@DianWang 尝试过了, 遍历时候的数组指针更加奇怪了. 按照PHP 7 对于数组指针说法是不会移动数组指针的, 而 PHP 5 是移动的.

$array = [0, 1, 2];
$ref =& $array; // Necessary to trigger the old behavior
foreach ($array as $val) {
    echo ' 当前指针为: ' . current($array) . "\n";
}

这个就不知道两者是否在foreach循环是循环副本数组的. PHP 7 输出则是 0 , 0 ,0 而 PHP 5 输出1, 2, false. 然而把ref = &array 注释, PHP 5 则输出 1 , 1, 1. 则数组指针移动有点奇怪了...

5年前 评论
DianWang

@WytheHuang 在秦明所著的《PHP7内核剖析》一书中对foreach有详细的解释,你可以买来看看,在这里我只说一句,不可以把foreach ($arr as $val) 中的$arr当作原数组的复制,原数组的复制是一个不可见的局部变量,你无法观测的。

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!