PHP匿名函数中$i总为最后一个值,因默认不捕获循环变量且use若未正确按值传递(如use ($i))会导致引用共享;箭头函数自动按值捕获但功能受限;use ($item)对对象仍为引用,需clone确保隔离。

PHP匿名函数里用$i为什么总是最后一个值
因为PHP匿名函数默认不自动捕获循环变量,use又没写对——它捕获的是变量的“引用”或“值”,不是当前迭代快照。常见现象是:循环生成10个闭包,全输出10(假设for ($i = 0; $i )。
use (&$i)和use ($i)的区别在哪
前者按引用捕获,所有闭包共享同一个$i,等循环结束再调用时,$i早已变成终值;后者按值捕获,但问题在于:如果在循环体里直接use ($i),PHP会复用同一个变量绑定,实际效果仍等同于引用捕获(尤其在for中)。正确做法是让每次迭代产生独立变量:
- 在循环内声明新变量:
$current = $i; $fn = function() use ($current) { return $current; }; - 或用立即执行匿名函数封装:
$fn = (function($x) { return function() use ($x) { return $x; }; })($i); - PHP 7.4+ 可用箭头函数简化:
$fns[] = fn() => $i;——但注意:箭头函数自动按值捕获,且只支持单表达式,不能替代复杂逻辑
foreach中use ($item)安全吗
相对安全,但仍有陷阱。如果$item是对象,use ($item)捕获的是对象引用(即使写use ($item)),后续修改对象属性会影响闭包内看到的值;如果要彻底隔离,得克隆:$copy = clone $item; $fn = function() use ($copy) { ... };。基础类型(int/string)则无此问题。
性能和可读性怎么权衡
频繁创建闭包时,每次额外声明$current会产生微小开销,但远小于逻辑错误的代价。比起用&$i再加unset($i)这类奇技淫巧,显式复制更易懂、更可靠。线上出过问题的代码,90%败在想省那行赋值。
立即学习“PHP免费学习笔记(深入)”;
真正容易被忽略的是:闭包捕获的变量作用域是定义时的,不是调用时的——哪怕你在闭包里global $i,也改不了捕获那一刻的快照。



















