栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > PHP

深入理解PHP之foreach

PHP 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深入理解PHP之foreach

语言基础

foreach 语法结构提供了遍历数组的简单方式。
php5之前, foreach仅能用于数组
php5+, 利用foreach可以遍历对象
foreach仅能够应用于数据和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。
有两种语法:


foreach (array_expression as $value) {
    // statement
}

foreach (array_expression as $value) :
    // statement
endforeach;

foreach (array_expression as $key => $value) {
    // statement
}

foreach (array_expression as $key => $value) :
    // statement
endforeach;

还能够自定义遍历对象!

当foreach开始执行时, 数组内部的指针会自动指向第一个单元. 这意味着不需要在foreach
循环之前调用reset() 由于foreach依赖内部数组指针, 在循环中修改其值将可能导致意外
的行为。

可以很容易通过在 $value 之前加上 & 来修改数组元素. 此方法将以引用 赋值, 而不是拷贝一个值。


$value的引用仅在被遍历的数组可以被引用时才可用(例如是个变量)。

以下代码无法运行:


Warning: 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。

foreach 虽然简单, 不过它可能出现一些意外行为, 特别是代码涉及到引用的时候。


问题研究

问题: 如下代码运行结果为何不是 2/4/6 ?
 &$v) {
    $v = $v * 2;
}

foreach ($arr as $k => $v) {
    echo $v, PHP_EOL;
}


我们可以认为 foreach($arr as &$v) 结构隐含了如下操作, 分别将数组当前的 键 和 值 赋值给 $k 和 $v。具体展开形如:

 $v) {
    $k = currentKey();
    $v = currentVal();
    // 继续运行用户代码
} 

根据上述理论, 现在我们重新来分析下第一个foreach:

循环 备注 $arr值
循环 1-1 由于$v是一个引用, 因此 $v = &$arr[0], $v = $v * 2 相当于 $arr[0] * 2 [2,2,3]
循环 1-2 $v = &$arr[1] [2,4,3]
循环 1-3 $v = &$arr[2] [2,4,6]
循环 2-1 隐含操作 $v = $arr[0] 被触发, 由于此时 $v 仍是 $arr[2] 的引用, 相当于 $arr[2] = $arr[0] [2,4,2]
循环 2-2 $v = $arr[1], 即$arr[2] = $arr[1] [2,4,4]
循环 2-3 $v = $arr[2], 即$arr[2] = $arr[2] [2,4,4]

如何解决此类问题呢? PHP手册上有一段提醒:

Warning: 数组最后一个元素的 $value 引用在 foreach 循环之后仍会保留。建议使用 unset() 来将其销毁。

 &$v) {
    $v = $v * 2;
}
unset($v);
foreach ($arr as $k => $v) {
    echo $v, PHP_EOL;
}


从这个问题可以看出, 引用很可能会伴随副作用。如果不希望无意识的修改导致数据内容变更, 最好及时unset掉这些引用。

PHP7新特性之foreach
  • foreach 循环对数组内部指针不再起作用, 在PHP7之前, 当数据通过foreach迭代时, 数组指针会移动。

版本 结果 说明
PHP5 int(1) int(2) bool(false) 数组指针会移动
PHP7 int(0) int(0) int(0) 数组指针不再移动
  • 按照值进行循环时, 对数组的修改是不会影响循环。
    foreach按照值进行循环的时候(by-value), foreach是对该数组的一个拷贝进行操作. 所以在循环过程中修改不影响循环结果。

版本 结果 说明
PHP5 int(0) int(2) 会将unset的数据跳过
PHP7 int(0) int(1) int(2) 对数组的改动不影响循环
  • 按照引用进行循环的时候, 对数组的修改会影响循环。

版本 结果
PHP5 int(0) int(2)
PHP7 int(0) int(2)
  • 对简单对象plain(non-Traversable)的循环。
    在简单对象的循环, 不管是按照值循环还是引用循环, 和按照引用对数组循环的行为是一样的, 不过对位置的管理会更加精确。

注 : 转载。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号