控制器中间件的only语法为:protected $middleware = ['中间件类名' => ['only' => ['method1', 'method2']]];仅限控制器内真实存在的public方法,区分大小写,不支持通配符或正则,TP6与TP8均适用且结构一致。

控制器中间件的only语法怎么写
ThinkPHP 6/8 中控制器级中间件支持按方法筛选执行,only不是独立函数或配置项,而是$middleware数组中某个中间件键值对的子配置。它必须配合类名(字符串或完整命名空间)一起使用,且只在控制器的$middleware属性里生效。
常见错误是把它当全局配置、路由链式调用参数,或误写成->only()方法 —— 这些都不合法。
-
$middleware必须定义为protected属性,不能是public或private - 数组结构必须是
['中间件类名' => ['only' => ['method1', 'method2']]],不能漏掉外层数组键 - 方法名区分大小写,且必须是控制器中真实存在的
public方法名(如index、create),不支持魔术方法或私有方法 - TP6 和 TP8 均不支持在
only中使用通配符(如'*edit')或正则表达式
正确示例:
<?php namespace app\controller;
<p>use think\Controller;<p>class User extends Controller
{
protected $middleware = [
\app\middleware\Auth::class => ['only' => ['profile', 'settings']],
\app\middleware\Log::class => ['only' => ['delete']],
];</p><pre class="brush:php;toolbar:false;">public function profile() { /* ... */ }
public function settings() { /* ... */ }
public function delete() { /* ... */ }
public function list() { /* 不触发任何中间件 */ }
}
only和except能同时用吗
不能。同一个中间件类在$middleware中只能指定only或except其中之一,二者互斥。框架解析时遇到两者共存会静默忽略only,仅保留except逻辑(TP6.3+ 及 TP8 行为一致)。
如果你需要“只对 A/B 方法启用 Auth,但对 B 方法额外加 Log”,应拆分为两个独立条目:
- 把
Auth设为only => ['A', 'B'] - 把
Log设为only => ['B']
不要试图合并:['Auth' => ['only' => ['A'], 'except' => ['B']]] —— 这会导致Auth在B方法上既不执行也不报错,行为不可控。
为什么only没生效?检查这三点
最常踩的坑不是语法写错,而是上下文不匹配:
- 控制器没继承
think\Controller(或 TP8 的think\mvc\Controller),$middleware属性会被完全忽略 - 中间件类本身
handle()方法没返回Response实例(比如忘了return $next($request)),导致后续流程中断,看起来像“没触发”,其实是卡死了 - 方法名拼写错误或用了别名(如路由绑定的
user/index对应控制器Index类的index()方法,但你在only里写了'index'却实际调用的是user路由绑定到User::show())
调试建议:在中间件handle()开头加echo 'auth run'; exit;,确认是否进入;再检查控制器方法是否真被访问到。
TP6 和 TP8 在only支持上有区别吗
没有本质区别。两者都要求$middleware是控制器属性、结构一致、不支持嵌套条件。唯一差异在于 TP8 对类型更敏感:
- TP8 默认开启严格类型检查,若中间件类
handle()方法签名缺少\think\Request或\Closure类型提示,在 PHP 8.1+ 下可能抛出TypeError而非静默失败 - TP6 允许
handle($request, $next)无类型提示,但建议补全,否则 IDE 提示弱、运行时易出错 - 多应用模式下,TP8 要求每个子应用的控制器单独定义
$middleware,不能依赖父应用配置;TP6 同样如此,但文档强调不足,容易忽略
真正容易被忽略的是:中间件注册后,必须确保该控制器被实际路由命中 —— 如果你用的是资源路由(Route::resource()),方法名是index/store等固定命名,only列表必须严格匹配这些名称,而不是你自定义的路由别名。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











