ThinkPHP 6 中 app_init 和 app_begin 已废弃,全局前置操作须迁至中间件;纯 PHP 设置可保留在 public/index.php;中间件需在 middleware.php 正确注册且注意执行顺序。

ThinkPHP 6 的 app_init 和 app_begin 已被废弃,别再往 event.php 里硬塞
ThinkPHP 6 起,全局“前置操作”概念彻底由中间件(Middleware)接管。你以前在 app_init 或 app_begin 事件里写的初始化逻辑(比如设置时区、加载配置、绑定容器对象),现在必须迁移到中间件中,否则启动阶段就失效——尤其是 app_init,连容器都还没创建完,根本没法用 think\Container。
常见错误现象:Call to a member function bind() on null,就是因为在 app_init 里调用了 Container::getInstance(),但此时容器实例尚未生成。
- 所有需要访问容器、请求、响应、配置的逻辑,必须放在中间件中(推荐
app_begin对应的中间件) - 纯 PHP 环境设置(如
date_default_timezone_set()、mb_internal_encoding())仍可保留在public/index.php开头,那里是最早执行点 - 不要试图在中间件里做耗时操作(如远程 HTTP 请求、大文件读取),会拖慢每个请求
如何注册一个真正生效的全局前置中间件
全局中间件 ≠ 写了中间件类就自动运行。它必须显式注册到应用生命周期的入口位置,且顺序不能错。
使用场景:统一日志记录、权限预检、多语言初始化、全局变量注入(如 $this->assign() 在模板中可用的变量)。
立即学习“PHP免费学习笔记(深入)”;
- 新建中间件类,例如
app/middleware/GlobalInit.php,实现__invoke方法 - 在
app/middleware.php中注册为全局中间件:return [ \app\middleware\GlobalInit::class, ]; - 确保该文件返回的是数组,且中间件类路径正确;写错路径不会报错,只会静默跳过
- 若需控制执行顺序(比如必须在
SessionInit之后),就把你的中间件放在这类依赖项之后
think\Middleware 与手动 app()->middleware() 注册的区别
两者都能加中间件,但生命周期和作用范围完全不同。
性能影响:通过 app()->middleware() 动态注册的中间件,每次请求都会重新解析、实例化,而 middleware.php 是框架启动时一次性加载,更轻量。
-
app()->middleware()->add()适合按条件动态追加(如开发环境加调试中间件),但别在生产环境滥用 -
middleware.php中注册的中间件,在Http应用初始化阶段即载入,能捕获从路由匹配前开始的所有流程 - 别在控制器或模型里调用
app()->middleware()—— 此时中间件链已固定,调用无效 - 错误示例:
app()->middleware()->add(\app\middleware\Log::class)放在控制器构造函数里 → 完全不生效
中间件里怎么安全访问 $request 和 $response?
中间件签名是 __invoke(Request $request, Closure $next),但很多人直接在中间件里调 input() 或 header(),结果发现值不对或者报错。
原因:TP6 的 Request 对象在中间件执行时已构建完成,但部分方法(如 param())依赖路由解析结果,而此时路由可能还没跑完。
- 安全访问方式:
$request->get()、$request->post()、$request->header()、$request->ip()都可用 - 避免用
$request->param()或$request->route(),除非你确定这个中间件注册在RouteCheck之后(比如用app/middleware.php默认顺序,它就在路由检查前) - 想改响应头?别直接
header(),用$response = $next($request)->header(...)链式修改 - 如果中间件里抛出异常,框架默认会走异常处理流程;但若你手动
exit或die,将绕过所有后续中间件和异常处理器
command.php 或命令类的 configure() 里处理。


















