不能直接赋值,必须用 with() 或 extend(),否则在 TP6.0+ 里会静默失效,TP5.1 可能报 Attempt to assign property 错误;Request 对象为只读设计,__set() 拦截赋值,硬写属性不进参数体系,param() 和验证器均不可见。

不能直接赋值,必须用 with() 或 extend(),否则在 TP6.0+ 里会静默失效,TP5.1 可能报 Attempt to assign property
为什么 $request->xxx = 'val' 不行
ThinkPHP 的 Request 对象是只读设计,底层有 __set() 拦截器。硬写属性不会报错(TP6.0+),但数据根本进不去参数体系;TP5.1 则可能直接抛出 Attempt to assign property 错误。控制器里调 $request->param('xxx') 或验证器校验时,完全看不到你“塞进去”的值。
with() 是最常用、最安全的传参方式
它把键值对注入到请求的 param 容器中,后续所有依赖参数解析的逻辑都能自然识别:
-
$request->param('user_id')可取 -
$request->only(['user_id', 'source'])包含它 - 验证器
Validate::check($data, $rule)默认校验的就是param()内容,所以自动生效 - 路由变量匹配(如
/:user_id)也能识别(需配合路由绑定)
正确写法示例:
立即学习“PHP免费学习笔记(深入)”;
$request = $request->with('user_id', $uid ?? null)->with('source', 'api');
return $next($request);
注意:必须在 return $next($request) 前调用;多次调用后一次覆盖前一次;分支逻辑里要确保每条路径都调用,否则漏掉就真没了。
extend() 适合挂载上下文类数据
它只是把属性挂在 Request 对象实例上,不进 param 体系:
-
$request->extend('auth_info', $authData)→ 后续可用$request->auth_info直接访问 -
$request->param('auth_info')返回null,验证器也校验不到 - 适合放权限标识、网关元信息、TraceID 这类“仅供当前请求内部消费、不参与业务参数流”的数据
别混用:想让控制器用 $request->param() 拿,或走验证规则,就只能选 with()。
TP5.1 和 TP6.x 的 with() 行为差异容易被忽略
TP5.1 的 with() 注入的数据,在 input('get.xxx') 或 input('post.xxx') 这类带前缀的读取方式里不可见;TP6.0+ 统一了语义,with() 数据在 param()、only()、except() 全部可见,但依然不会出现在带前缀的 input() 调用中——这点常导致调试时以为“没传进去”,其实是读取方式错了。



















