应使用with()方法向$request注入自定义属性,它将数据存入param体系,使控制器可通过$request->param('key')获取,并支持验证器自动校验;extend()仅扩展对象属性,不参与请求解析链。

ThinkPHP中间件里怎么给$request加自定义属性
不能直接给$request对象赋新属性——它被设计为只读,硬写会触发__set拦截并静默失败或报错(取决于版本)。真正可行的方式是用with()方法挂载数据,或通过extend()扩展属性容器。
-
with()是最推荐的:它把键值对存进$request->getParams()的底层容器,后续在控制器里用$request->param('key')或$request->only(['key'])能直接取到 - 别用
$request->xxx = 'val',TP6.0+会忽略,TP5.1可能报Attempt to assign property - 如果需要全局可读且不参与参数合并(比如权限上下文),改用
$request->extend('auth_info', $data),之后用$request->auth_info访问(注意:这个属性不会出现在param()结果里)
为什么with()比extend()更常用
因为绝大多数场景要让中间件注入的数据“自然融入请求流”:控制器想用就用,验证规则能自动识别,路由变量也能匹配。而with()注入的数据会进入param体系,extend()只是挂在对象上,不参与请求解析链。
-
with('user_id', 123)→$request->param('user_id')可取,$request->only(['user_id'])包含它 -
extend('user_role', 'admin')→$request->user_role可取,但$request->param('user_role')返回null - 验证器
Validate::check($data, $rule)默认只校验param()内容,所以用with()才能被自动校验
中间件中调用with()的正确时机
必须在return $next($request);之前调用,且只能调用一次生效(多次调用后一次覆盖前一次)。如果中间件有分支逻辑,得确保所有路径都调用了with(),否则部分请求会漏掉属性。
- 错误写法:
if ($token) { $request->with('uid', $uid); } return $next($request);→ 无token时uid根本不存在 - 正确写法:
$request = $request->with('uid', $uid ?? null); return $next($request); - TP6.3+支持链式:
return $next($request->with('uid', $uid)->with('source', 'api'));
容易被忽略的兼容性细节
TP5.1和TP6.x的with()行为不一致:TP5.1的with()只影响当前请求生命周期内的param(),但不会透传到input();TP6.0+统一了语义,with()注入的键在param()、only()、except()里都可见,但依然不会出现在input('get.') 或input('post.')这种带前缀的读取中。
- 想让
with()数据也响应input('custom'),得额外调用$request->filter(['custom' => $val])(不推荐,易混淆) - 调试时别只看
dump($request),它不显示with()内容;用dump($request->param())确认是否注入成功 - 如果中间件嵌套多层,后执行的中间件
with()会覆盖前面同名键,没有合并逻辑
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











