foreach 與 reference 的雷
前陣子公司定期技術研討會時,有人提出了一個問題。
$arr = [1, 2, 3];
foreach ($arr as &$a) {}
foreach ($arr as $a) {}
var_dump($arr);
考慮以上程式碼執行結果,試問陣列 $arr 在執行結束後的值會是如何?
註:執行環境 PHP 7.1 without swoole
結果:$arr 的值為 [1, 2, 2]
緣由
在 PHP 中,foreach 結束後,迴圈中的索引值(index)及內容(value)並不會被消滅。
$a = [, , ];
foreach ($a as $v) {} var_dump($v); // int(3) foreach ($a as $k => $value) {} var_dump($k, $value); // int(2), int(3)
同理,foreach ($a as &$v) {} 時,在迴圈結束後 $v 值不會被消滅,其值仍是參考於(referenced by)陣列中的最後一個值,執行範例如下:
$a = [1, 2, 3];
foreach ($a as &$v) {} var_dump($a);
/*
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
&int(3)
}
*/
如果在迴圈結束後變更 $v 值,則陣列中的最後一個值也會一併被變更。
解決方法
在使用 foreach ($a as &$v) {} 這類寫法後,應手動 unset($v) 以避免潛在問題發生。
$a = [1, 2, 3];
foreach ($a as &$v) {
// do something...
}
unset($v);
http://php.net/manual/en/control-structures.foreach.php
为了能够直接修改循环中的数组元素,在$ value之前 加上&。在这种情况下,该值将通过引用分配 。
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>
警告
即使在foreach循环之后,$ value和最后一个数组元素的 引用仍然存在。建议通过unset()销毁它。否则您将遇到以下行为:
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8) // without an unset($value), $value is still a reference to the last item: $arr[3] foreach ($arr as $key => $value) {
// $arr[3] will be updated with each value from $arr...
echo "{$key} => {$value} ";
print_r($arr);
}
// ...until ultimately the second-to-last value is copied onto the last value // output:
// 0 => 2 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 2 )
// 1 => 4 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 4 )
// 2 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
// 3 => 6 Array ( [0] => 2, [1] => 4, [2] => 6, [3] => 6 )
?>
foreach 與 reference 的雷的更多相关文章
- PHP 高级面试115题汇总(含答案)
1.给你四个坐标点,判断它们能不能组成一个矩形,如判断 ([0,0],[0,1],[1,1],[1,0]) 能组成一个矩形.勾股定理,矩形是对角线相等的四边形.只要任意三点不在一条直线上,任选一点,求 ...
- C# 动态修改dll的签名 以及修改引用该dll文件的签名
在读取RedisSessionStateProvider配置 提到用mono ceil 来修改程序集以及它的签名,里面GetPublicKey 和GetPubliKeyToken 方法里面那个字符串的 ...
- 仿windows8 开始菜单 实现HubTileBase 以及仿鲜果联播实现 PulsingTile(脉冲磁贴)
http://blog.csdn.net/wangrenzhu2011/article/details/8750820 (转) 本文章将以如何实现 开始菜单上的tile 为主. 该控件代码经过测试可直 ...
- PDOStatement::bindParam的一个陷阱
废话不多说, 直接看代码: <?php $dbh = new PDO('mysql:host=localhost;dbname=test', "test"); $query ...
- PHP 使用用户自定义的比较函数对数组中的值进行排序
原文:PHP 使用用户自定义的比较函数对数组中的值进行排序 usort (PHP 4, PHP 5) usort — 使用用户自定义的比较函数对数组中的值进行排序 说明 bool ...
- 解析.NET对象的跨应用程序域访问--AppDomain(上篇)
在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...
- 一个 C# 文件权限的帮助类
直接贴代码了: FilePermissionHelper.cs using System.Collections.Generic; using System.IO; using System.Secu ...
- 解析.NET对象的跨应用程序域访问(上篇)
在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...
- Revit API射线法读取空间中相交的元素
Revit API提供根据射线来寻找经过的元素.方法是固定模式,没什么好说.关键代码:doc.FindReferencesWithContextByDirection(ptStart, (ptEnd ...
随机推荐
- 修改CentOS服务器时间为北京时间
购买了VPS,CentOS系统,发现服务器时间与北京时间往往不一致,存在时差. [clive@server workspace]$ date 2018年 05月 30日 星期三 02:02:47 UT ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- javaScript 设计模式之中介者模式示例
飞机把注册信息放到铁塔里,发送数据到铁塔,报告其它的飞机一些信息. var feiji = function( name ){ this.name = name; } feiji.prototype. ...
- js内置对象-Object
1)Object构造函数的方法 返回指定对象的原型对象 Object.getPrototypeOf(mymap); /*{featureStyle: {…}, selfLayersCount: nul ...
- CSS 定位与Z-index
position: static Z-index 固定是0 position: absolute/relative/fixed Z-index 有效 在层叠显示上,所有static定位元素看作 ...
- 9.Odoo产品分析 (二) – 商业板块(4) –讨论(1)
查看Odoo产品分析系列--目录 讨论模块就是一个信息记录和消息提醒的功能,在登录到odoo平台的时候第一个界面就是它: 1. 收件箱 收件箱,登录者的邮箱管理,并显示未读邮件数量: 点击上面 ...
- Deep Learning - 3 改进神经网络的学习方式
反向传播算法是大多数神经网络的基础,我们应该多花点时间掌握它. 还有一些技术能够帮助我们改进反向传播算法,从而改进神经网络的学习方式,包括: 选取更好的代价函数 正则化方法 初始化权重的方法 如何选择 ...
- 【数据分析】线性回归与逻辑回归(R语言实现)
文章来源:公众号-智能化IT系统. 回归模型有多种,一般在数据分析中用的比较常用的有线性回归和逻辑回归.其描述的是一组因变量和自变量之间的关系,通过特定的方程来模拟.这么做的目的也是为了预测,但有时也 ...
- NAT穿越(一) NAT类型
NAT分为四种类型: (1)完全透明NAT(Full Cone NAT): 从内部主机 (IN IP ipa) +端口(IN PORT porta) 发送的数据映射为 IP(OUT IP IPA) ...
- Java 关键字 速查表
访问控制:private 私有的protected 受保护的public 公共的 类.方法和变量修饰符abstract 声明抽象class 类extends 扩允,继承final 终极,不可改变的im ...