最简可用的ThinkPHP路由分组必须用字符串前缀加闭包函数,且仅支持闭包写法;中间件需链式挂载分组末尾;变量规则和URL后缀可批量设置;前缀推荐用->prefix();url()生成需命名路由、指定命名空间并清除缓存。

最简可用的 ThinkPHP 路由分组,必须同时满足两个硬性条件:Route::group() 的第一个参数是字符串前缀,第二个参数是闭包函数——缺一不可,否则路由根本不会注册。
闭包写法是唯一推荐方式
TP5.1+ 和 TP6/8 都只稳定支持闭包定义分组,数组式写法(如 Route::group('api', ['user' => 'api/User/read']))在新版中已被废弃,静默失效,不报错也不匹配。
- ✅ 正确:用闭包包裹所有子路由,路径不加开头斜杠(
Route::get('user/:id', ...)),前缀自动拼接 - ❌ 错误:闭包为空、漏写括号、或把控制器路径写成
User/read(缺命名空间前缀,实际类找不到) - ⚠️ 注意:分组名
'api/v1'会直接作为 URL 前缀,别再在子路由里重复写'/api/v1/user',否则变成双斜杠//api/v1/user导致 404
中间件必须链式挂载在分组末尾
中间件不是写在闭包里的某条路由上,而是要作用于整个分组对象。写错位置会导致只对最后一条路由生效,甚至抛出 Call to a member function middleware() on null。
- ✅ 正确:
Route::group('api', function () { /* 子路由 */ })->middleware(['Auth', 'Log']) - ⚠️ 危险:
Route::group('api', function () { Route::get('user', ...)->middleware('Auth'); })—— 只影响这一条,且容易误判为全组受控 - 中间件类名需可解析,比如
Auth::class对应app\middleware\Auth,且handle()方法签名必须匹配框架版本
统一约束参数和后缀,别每条路由重复写
分组支持批量设置变量规则和 URL 后缀,避免在每条子路由里重复调用 ->pattern() 或 ->ext()。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
立即学习“PHP免费学习笔记(深入)”;
-
->pattern(['id' => '\d+', 'name' => '\w+']):所有含:id或:name的子路由自动应用正则约束,不匹配直接 404 -
->ext('json'):该分组下所有路由自动识别.json后缀(如/api/user/1.json),无需手动解析请求头 - 更安全的前缀写法:
->prefix('api/v1/'),把路径前缀从分组名移到prefix参数里,避免分组名被误当 URL 段
url() 生成链接不带前缀?检查这三点
加了分组前缀,但 url('user/index') 还是输出 /user/index,不是配置问题,而是 URL 生成机制没对齐。
- 路由没显式命名:
Route::get('user', 'User/index')->name('api.user'),否则url()只按控制器/方法硬拼,无视分组 - 资源路由未指定命名空间:
Route::resource('user', 'User')在分组内,控制器默认找app\controller\User,得加->namespace('api') - 缓存没清:改完路由后必须运行
php think route:clear,否则url()读的是旧缓存里的规则
最容易被忽略的是:分组名 ≠ 路径前缀的最终表现形式,它只是注册时的逻辑标识;真正影响 URL 匹配和生成的,是闭包内子路由的写法、是否命名、以及缓存是否刷新。这三个点卡住一个,整个分组就“看起来没生效”。


















