PHP 循环和&引用陷阱

前言

很久之前给电商公司写过一个计算销售人员绩效的方法,那复杂度,懂的都懂。实现时就发生了对同一个数组多次操作并改值的需求,也踩到了PHP作为弱类型语言和引用相关的坑,花了好久才找到问题。今日就做个记录。

陷阱的简单描述

  • PHP的循环,没有单独的生命周期,循环产生的变量,在循环结束后不会被释放。
  • 循环产生的值变量,如果与已存在的引用变量同名,会给对应的引用变量赋值。

现象

我们先看一段代码,可以根据描述思考下,这段代码的输出是什么?

代码

$a = [1, 2];
$b = [3, 4];
$i = &$a[0];
foreach ($a as &$c) {}
echo 'i: ', var_dump($i);
echo 'c: ', var_dump($c);
echo 'a: ', var_dump($a);
foreach ($b as $i => $c) {
echo $i . ' changed a: ', var_dump($a);
}
echo 'b end,changed a: ', var_dump($a);

输出

i: int(1)
c: int(2)
a: array(2) {
[0]=>
&int(1)
[1]=>
&int(2)
}
0 changed a: array(2) {
[0]=>
&int(0)
[1]=>
&int(3)
}
1 changed a: array(2) {
[0]=>
&int(1)
[1]=>
&int(4)
}
b end,changed a: array(2) {
[0]=>
&int(1)
[1]=>
&int(4)
}

处理思路

由于这是源码带来的特性,所以解决思路并不是修复它,而是规避它。

  • 一、尽量避免使用同名的变量,即便是在循环中的“临时变量”。
  • 二、循环完毕后,使用unset()释放循环产生的变量。

这两个特性当然也可以利用起来实现某些特殊的需求,比如:

  • foreach($arr as $i => $item) {} 循环后,$i可以当做count($arr)-1来使用,$item可以当做end($arr)来使用。这会节省一些开销。
  • 当需要保留对end($arr)的引用时。
  • 当需要覆盖之前的某个变量时。

这其实类似于在switch/case中,特意不使用break一样。可以根据特定的场景进行使用,但可读性较差,知其然,谨慎选择。

posted @   cy_b  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示