ci4中间件构造函数不支持依赖注入,必须在handle()方法中通过services::xxx()手动获取服务实例。因中间件由框架直接new创建,非容器管理,故类型提示无效;handle()中才具备完整请求上下文,可安全调用services::session()、database()等。

Services 在中间件里不能靠构造函数参数自动注入,CI4 的中间件类不走依赖注入容器的自动解析流程。你得手动调用 \Config\Services 静态工厂方法来获取服务实例。
中间件构造函数不支持类型提示自动注入
CI4 的中间件(比如 app/Controllers/Middleware/AuthMiddleware.php)是被框架直接 new 出来的,不是通过服务容器创建的。所以即使你写:public function __construct(Session $session),$session 也会是 null 或触发 fatal error —— 框架根本不会尝试解析这个参数。
正确做法:在 handle() 方法里用 Services::xxx() 获取服务
中间件的核心逻辑写在 handle() 方法里,这里才是安全使用服务的地方。因为此时请求上下文已初始化,Services 工厂能正常工作。
-
Services::session()可以安全调用,会返回已启动的会话实例 -
Services::database()在 handle 中可用,但注意连接开销,非必要不提前建连 -
Services::cache()同样支持,适合做令牌校验、限流等前置缓存判断
示例:
public function handle(RequestInterface $request, $next)
{
$session = \Config\Services::session();
if (! $session->has('user_id')) {
return redirect()->to('/login')->with('error', '请先登录');
}
$db = \Config\Services::database();
// ⚠️ 注意:这里只是获取连接对象,没执行查询就不耗资源
return $next($request);
}
为什么不能在中间件构造函数里调用 parent::__construct()
中间件类不继承 Controller,也没有 parent::__construct() 可调。试图加这一行会报 Fatal error: Call to undefined method。CI4 的中间件是纯 PSR-15 兼容组件,和控制器生命周期完全隔离。
想复用控制器里的服务初始化逻辑?别硬搬
有些开发者把控制器里 $this->session = Services::session() 的写法复制到中间件属性里,结果发现属性始终为空 —— 因为中间件没有 $this->session 这种自动挂载机制。所有服务都必须在 handle() 内按需获取,且每次请求只取一次即可。
真正容易被忽略的是:中间件执行顺序早于控制器构造函数,所以它看到的会话状态,就是用户本次请求最原始的状态;任何在控制器里修改的 session 数据,中间件是看不到的。











