CI4服务容器注入后对象为null,根本原因是类未被容器成功实例化,常见于路径与命名空间不匹配、接口未绑定实现、构造函数含标量参数未用工厂注册等情况。

CI4 服务容器注入后对象为 null 的典型表现
控制器里调用 $this->userRepository->find(1) 报错 Call to a member function find() on null;或者 var_dump($this->userRepository) 输出 NULL。这不是模型没查到数据,而是类根本没被容器成功实例化——连构造函数都没执行。
为什么 $this->userRepository 是 null 而不是报错“No service for type”
CI4 容器默认只自动解析“已注册服务”或“有完整命名空间且能被反射准确识别的类”。以下情况会导致静默失败(不报错但注入 null):
- 类文件路径与命名空间不匹配,比如命名空间是
App\Repositories\UserRepository,但文件实际放在app/Models/UserRepository.php - 控制器构造函数中用了接口类型提示(如
UserRepositoryInterface),但没在app/Config/Services.php里绑定实现类 - 类依赖了标量参数(如
string $env),而容器无法自动提供字符串值,又没用工厂方式注册 - 类文件存在语法错误或未声明
namespace,导致反射失败,容器跳过该类
验证和修复自定义类注入的三步实操
别猜,直接验证容器是否“认识”你的类:
- 在控制器里加一行:
var_dump(\Config\Services::has('App\Repositories\UserRepository'));—— 返回false就说明容器根本没加载它 - 检查
app/Repositories/UserRepository.php是否有正确的namespace App\Repositories;,且类名与文件名一致(UserRepository) - 在
app/Config/Services.php的initialize()方法里显式注册:$container->singleton('App\Repositories\UserRepository', 'App\Repositories\UserRepository');
如果依赖接口,必须手动绑定:$container->singleton('App\Repositories\UserRepositoryInterface', 'App\Repositories\DatabaseUserRepository');
构造函数里混用自动解析类和运行时参数是最大雷区
下面这种写法必然失败:
public function __construct(UserRepository $repo, string $apiKey) { ... }
CI4 不支持混合注入:容器能解析 UserRepository,但不知道该给 $apiKey 填什么。结果是整个构造函数被跳过,$this->repo 变成 null。正确做法是把 $apiKey 移到方法参数里,或改用工厂注册:
$container->singleton('App\Services\ApiClient', function($container) {
return new \App\Services\ApiClient(
$container->get('App\Repositories\UserRepository'),
config('App\Config\MyConfig')['api_key']
);
});
真正容易被忽略的是:哪怕类文件存在、命名空间正确,只要构造函数里带一个标量参数,又没走工厂注册,容器就直接放弃实例化——不会报错,也不会警告,只会给你一个安静的 null。

















