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

$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. angular ng-click防止重复提交

    方法一:点击后,让button的状态变为disable js指令: .directive('clickAndDisable', function() { return { scope: { click ...

  2. uni-app (1) 安装与运行。

    安装: 直接到官网安装. 到插件市场下载一个模版. 新建项目的时候有提示链接: 找一个模版用于测试,或者在创建的时候选一个内置模版. 运行:第一次运行的时候有几个地方需要配置,这里因为只是用到了微信小 ...

  3. vuejs2.0实现一个简单的分页

    用js实现的分页结果如图所示: css .page-bar{ margin:40px; } ul,li{ margin: 0px; padding: 0px; } li{ list-style: no ...

  4. 洛谷P4213 Sum(杜教筛)

    题目描述 给定一个正整数N(N\le2^{31}-1)N(N≤231−1) 求ans_1=\sum_{i=1}^n\phi(i),ans_2=\sum_{i=1}^n \mu(i)ans1​=∑i=1 ...

  5. 基于Docker的TensorFlow机器学习框架搭建和实例源码解读

    概述:基于Docker的TensorFlow机器学习框架搭建和实例源码解读,TensorFlow作为最火热的机器学习框架之一,Docker是的容器,可以很好的结合起来,为机器学习或者科研人员提供便捷的 ...

  6. 用ABP只要加人即可马上加快项目进展(二) - 分工篇

    2018年和1998年其中两大区别就是: 前端蓬勃发展, 前后端分离是一个十分大的趋势. 专门的测试人员角色被取消, 多出了一个很重要的角色, 产品经理   ABP只要加入即可马上加快项目进展, 选择 ...

  7. Elasticsearch alias别名管理小结

    Elasticsearch alias别名管理小结 By:授客 QQ:1033553122 建创测试数据 1 创建别名 2 移除别名 3 创建测试数据 4 批量操作 5 例1. 5 例2. 把多个索引 ...

  8. Android为TV端助力 转载:android MVC设计模式

    Controller控制器 import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle ...

  9. SQL学习总结-思维导图

  10. (网页)HTMl5的sessionStorage和localStorage

    百度上百度的,记录一下: html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage. sessionStorage用于本地存储一个会话(sessi ...