为什么这个代码在 PHP 7.0 和 PHP 5.6 得出结果不同?

2018-04-18 21:38:03 +08:00
 WytheHuang
$arr = array(0,1,2,3,4,5);
$ref = &$arr;
foreach($arr as $value){
    $arr = array();
    echo $value;
}

在 PHP7.0 中, 输出 012345, 而在 PHP 5 中 输出 0. PHP7.0 提及到 foreach 改变的有三点.

  1. foreach 不再改变内部数组指针.
  2. foreach 通过值遍历时,操作的值为数组的副本
  3. foreach 通过引用遍历时,有更好的迭代特性

看到第二点有点懵, 我看一些资料都说 PHP 5 在 foreach 是操作数组副本的, 那么官方手册写这句话有什么含义还是有所变化? 为何会导致 PHP7.0 和 PHP 5 的结果截然不同?

3705 次点击
所在节点    PHP
8 条回复
carlclone
2018-04-18 22:09:20 +08:00
二、按照值进行循环的时候,foreach 是对该数组的拷贝操作

foreach 按照值进行循环的时候(by-value),foreach 是对该数组的一个拷贝进行操作。这样在循环过程中对数组做的修改是不会影响循环行为的。

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

http://www.jb51.net/article/91331.htm 这里第二点 , 以前应该不是拷贝了
WytheHuang
2018-04-18 22:35:57 +08:00
@carlclone 但是, PHP 5 以前不是拷贝的话, 那么下面这个代码应该跟 PHP 7 不一样
```
$arr = array('a','b','c');
foreach ($arr as $key=> $value) {
$arr[] = 'd';
print_r($arr);
var_dump($key,$value);
}
```
然而输出其结果也是一样的.
> Array ( [0] => a [1] => b [2] => c [3] => d )
int(0) string(1) "a"
Array ( [0] => a [1] => b [2] => c [3] => d [4] => d ) int(1)
string(1) "b"
Array ( [0] => a [1] => b [2] => c [3] => d [4] => d [5] => d )
int(2) string(1) "c"
而且上面代码$ref = &$array 为什么会出现这样结果, 不是很明白.
jfcherng
2018-04-18 23:05:08 +08:00
2. foreach by-value operates on a copy of the array

When used in the default by-value mode, foreach will now operate on a copy of the array being iterated rather than the array itself. This means that changes to the array made during iteration will not affect the values that are iterated.

把完整的官方說明看完啊,不要只看標題
WytheHuang
2018-04-19 09:31:02 +08:00
DukeAnn
2018-04-19 10:18:09 +08:00
PHP 7 你可以这么理解,`foreach` 把整个数组隐式的镜像了一份给自己用,所以无论你怎么修改原数组都不会影响到 `foreach` 镜像数据,但是你打出来你原始数组是已经被修改了的。

```php
$arr = array(0,1,2,3,4,5);
$ref = &$arr;
foreach($arr as $key => $value){
$arr = array();
echo "foreach 镜像数据:" . $value;
echo "\n";
echo "原始数组:";
var_dump($arr);
}
```

运行结果:
foreach 镜像数据:0
原始数组:array(0) {
}
foreach 镜像数据:1
原始数组:array(0) {
}
foreach 镜像数据:2
原始数组:array(0) {
}
foreach 镜像数据:3
原始数组:array(0) {
}
foreach 镜像数据:4
原始数组:array(0) {
}
foreach 镜像数据:5
原始数组:array(0) {
}
WytheHuang
2018-04-19 10:34:24 +08:00
@DukeAnn PHP 7 这样可以理解, 而在 PHP 5 中的, 加了引用. 情况有所不同的, 实时随着数组改变的, 就是这一点让我觉得很郁闷.
```
// PHP 输出: foreach 镜像数据:0 原始数组:array(0) { }
$arr = array(0,1,2,3,4,5);
$ref = &$arr;
foreach($arr as $key => $value){
$arr = array();
echo "foreach 镜像数据:" . $value;
echo "\n";
echo "原始数组:";
var_dump($arr);
}
```
DukeAnn
2018-04-19 10:42:03 +08:00
@WytheHuang 这个没看具体文档,但是根据当前输出的情况和最近看 Go 语言的遍历机制,我推测 php5 应该是只缓存了当前遍历这一次的 $value 和 $key,而且遍历会改变原始数组的内部指针位置从而拿到下一个需要遍历的键值对,进行镜像。所以在 foreach 内部将数组赋值为空,第二次遍历就凉了。
DukeAnn
2018-04-19 10:43:13 +08:00
@WytheHuang 个人推测,具体的可以自己实践一下,或者查查文档。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/447950

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX