前陣子公司定期技術研討會時,有人提出了一個問題。

$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 的雷的更多相关文章

  1. PHP 高级面试115题汇总(含答案)

    1.给你四个坐标点,判断它们能不能组成一个矩形,如判断 ([0,0],[0,1],[1,1],[1,0]) 能组成一个矩形.勾股定理,矩形是对角线相等的四边形.只要任意三点不在一条直线上,任选一点,求 ...

  2. C# 动态修改dll的签名 以及修改引用该dll文件的签名

    在读取RedisSessionStateProvider配置 提到用mono ceil 来修改程序集以及它的签名,里面GetPublicKey 和GetPubliKeyToken 方法里面那个字符串的 ...

  3. 仿windows8 开始菜单 实现HubTileBase 以及仿鲜果联播实现 PulsingTile(脉冲磁贴)

    http://blog.csdn.net/wangrenzhu2011/article/details/8750820 (转) 本文章将以如何实现 开始菜单上的tile 为主. 该控件代码经过测试可直 ...

  4. PDOStatement::bindParam的一个陷阱

    废话不多说, 直接看代码: <?php $dbh = new PDO('mysql:host=localhost;dbname=test', "test"); $query ...

  5. PHP 使用用户自定义的比较函数对数组中的值进行排序

    原文:PHP 使用用户自定义的比较函数对数组中的值进行排序 usort (PHP 4, PHP 5) usort —      使用用户自定义的比较函数对数组中的值进行排序 说明       bool ...

  6. 解析.NET对象的跨应用程序域访问--AppDomain(上篇)

    在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...

  7. 一个 C# 文件权限的帮助类

    直接贴代码了: FilePermissionHelper.cs using System.Collections.Generic; using System.IO; using System.Secu ...

  8. 解析.NET对象的跨应用程序域访问(上篇)

    在目前的项目开发中,分布式开发已经逐渐成为主流.一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目.这句话虽然有些过激,但是随着人们对效率的要求在提高,以及产品需要提升用户体验.只有 ...

  9. Revit API射线法读取空间中相交的元素

    Revit API提供根据射线来寻找经过的元素.方法是固定模式,没什么好说.关键代码:doc.FindReferencesWithContextByDirection(ptStart, (ptEnd  ...

随机推荐

  1. BootStrapTable 错误

    异常:Cannot read property 'field' of undefined 场景:使用BootStrapTable展示数据时,控制台报错 解决:给table加上 thead 和 tbod ...

  2. 用Python实现Zabbix-API 监控

    做运维的朋友应该知道,公司IDC机房经常有上架.下架.报修和报废的服务器.如果服务器数量很多的时候很容易造成监控遗漏.       大的互联网公司把监控系统和CMDB(资产管理系统|配置管理数据库系统 ...

  3. Nginx之OCSP stapling配置

    摘要: 正确地配置OCSP stapling, 可以提高HTTPS性能. 什么是OCSP stapling? OCSP的全称是Online Certificate Status Protocol,即在 ...

  4. 网页导航栏 html + css的代码实现

    一般来讲,我们的网页导航栏是这么个模式来构建在结构上:1.首先我们需要给导航栏的div 给个类名 一般为nav2.然后就是一个无序表格 3.由于导航栏的文字一般都是链接用来跳转页面 要在li里面包含一 ...

  5. 51nod"省选"模测 A 树的双直径(树形dp)

    题意 题目链接 Sol 比赛结束后才调出来..不多说啥了,就是因为自己菜. 裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天.. 转移都在代码注释里 毒瘤题目卡空 ...

  6. spring-boot-starter-thymeleaf对没有结束符的HTML5标签解析出错

    springboot 在使用thymeleaf 作为模板时,当出现未关闭标签时,如下所示代码,标签没有关闭. <link href="plugin/layui/css/layui.cs ...

  7. vue2 设置网页title的问题

    好东东,没个标题看着多难受 看到1文章  http://blog.csdn.net/qishuixian/article/details/72912368 推荐使用 vue-wechat-title插 ...

  8. Retrieve OpenGL Context from Qt 5.5 on OSX

    In the latest Qt 5.5, the QOpenGLWidget is much better and has less bugs than the QGLWidget, but it ...

  9. 测试系统工程师TSE的职责与培养

    测试系统工程师TSE的职责与培养 研发资深顾问 杨学明 如今,国内所有的研发型的公司都有测试部门,无论测试团队大小,都有测试组长,测试经理,测试工程师等头衔,但随着产品和业务的质量要求越来越高,产品的 ...

  10. JHipster生成微服务架构的应用栈(四)- 网关微服务示例

    本系列文章演示如何用JHipster生成一个微服务架构风格的应用栈. 环境需求:安装好JHipster开发环境的CentOS 7.4(参考这里) 应用栈名称:appstack 认证微服务: uaa 业 ...