
本文深入解析 PHP 闭包中 use() 语法对变量的传递方式,重点说明为何需用 &$list 显式传引用才能在闭包内修改外部变量,而 $request 和 $user 可直接传值,本质源于 PHP 的变量作用域与内存管理机制。
本文深入解析 php 闭包中 `use()` 语法对变量的传递方式,重点说明为何需用 `&$list` 显式传引用才能在闭包内修改外部变量,而 `$request` 和 `$user` 可直接传值,本质源于 php 的变量作用域与内存管理机制。
在 Laravel 开发中,我们常使用集合(Collection)配合 each()、map() 等高阶函数进行数据处理。如下代码看似简洁,却暗含关键细节:
public function index(Request $request, User $user)
{
$list = collect();
$someRelations()->each(function ($val) use (&$list, $request, $user) {
$list->push($val->transform()); // ✅ 修改外部 $list
});
dd($list); // 此处能获取到累积结果
}这里 &$list 前的 & 符号至关重要——它表示按引用传递(pass by reference),而 $request 和 $user 是按值传递(pass by value)。二者行为差异的根本原因并非 Laravel 框架特性,而是 PHP 语言底层的作用域与内存模型决定的。
▸ 为什么 $list 必须加 &?
PHP 中,闭包通过 use 子句捕获外部变量时,默认创建该变量的副本(copy),而非指向原变量的引用。这意味着:
- 若 $list 不加 &,闭包内对 $list 的任何操作(如 push()、add())仅作用于副本,原始 $list 在闭包外保持不变;
- 加上 &$list 后,闭包获得的是 $list 变量本身的内存地址,所有修改实时同步至外部作用域。
验证示例:
// ❌ 不加 &:外部变量不受影响
$x = collect(['a']);
(function() use ($x) {
$x->push('b');
echo $x->count(); // 输出 2
})();
echo $x->count(); // 仍为 1 → 副本已销毁,原始未变
// ✅ 加 &:外部变量被真实修改
$y = collect(['a']);
(function() use (&$y) {
$y->push('b');
echo $y->count(); // 输出 2
})();
echo $y->count(); // 输出 2 → 引用生效▸ 为何 $request 和 $user 可不加 &?
Request 和 User(Eloquent Model)对象在 PHP 中属于引用类型(object types)。自 PHP 5 起,对象变量默认存储的是对象标识符(handle),而非实际数据拷贝。因此:
- 即使按值传递(use ($request)),闭包内 $request 仍指向同一 Request 实例;
- 对其调用方法(如 $request->input()、$request->all())不会改变 $request 变量本身,仅读取或间接操作其内部状态;
- 若需替换整个对象(如 $request = new Request(...)),则必须加 &;但日常使用中极少需要重赋值对象变量。
✅ 安全实践建议:
- 对可变容器类(如 Collection、array、stdClass 属性)需显式传引用(&$var)以累积修改;
- 对不可变或只读用途的对象(如 $request, $user),按值传递更清晰、安全,避免意外覆盖;
- 避免滥用引用:过度使用 & 可能导致逻辑耦合、调试困难,应明确“谁负责修改”这一职责边界。
⚠️ 注意:PHP 7.4+ 引入了箭头函数(fn()),其 use 自动继承外部作用域变量,但仍遵循相同引用规则——若需修改外部变量,仍需显式 &$var。
理解这一机制,不仅能写出更可靠的 Laravel 数据处理逻辑,更是掌握 PHP 语言本质的关键一环。


















