ControllerFactory 通过服务容器自动注入依赖实例化控制器,仅调用无参构造函数;所有依赖须通过类型提示声明并注册到容器,不可手动传参。

ControllerFactory 怎么实例化控制器?它不走构造函数参数
CodeIgniter 4 的控制器不是靠 new UserController($dep) 直接创建的,而是由 ControllerFactory 类统一管理。这个工厂类只调用无参构造函数——哪怕你写了带参数的 __construct(),框架也**不会传任何参数进去**,直接抛 Too many arguments to method 错误。
原因很简单:路由分发阶段,框架无法预知你要传什么值(比如 URI 参数、中间件结果、运行时配置),所以必须把构造函数“清空”成安全入口。所有依赖必须通过服务容器自动注入,而不是手动塞参数。
- 控制器里写
public function __construct(SomeService $s)→ 运行时报错 - 正确写法是留空构造函数,靠类型提示让容器自动填值:
protected $someService;+public function __construct(SomeService $someService)(仅当该类已注册进服务容器且类型能被反射识别) - 如果依赖未注册或类型模糊(比如接口没绑定实现),容器 fallback 到
new SomeService(),但前提是其构造函数本身可被 public 调用
service() 函数和 $container->get() 有什么区别?
service() 是 CodeIgniter 4 提供的全局辅助函数,本质就是对服务容器的封装调用;而 $container->get() 是直接操作 CodeIgniter\Services 实例。两者最终都走同一套解析逻辑,但行为细节不同:
-
service('logger'):从app/Config/Services.php的静态方法中获取,支持单例缓存,且会自动触发服务初始化(比如连接数据库、加载配置) -
$container->get('LoggerInterface'):按类型名查找,依赖反射 + 绑定注册,适合在自定义服务提供者或测试中使用 - 用
service()拿不到未在Services.php中显式定义的服务;用get()可以拿任意已注册类型,但若没绑定,会尝试 new 实例——此时若目标类构造函数是protected,就直接失败
为什么 myClassA1 的 protected __construct() 在 $CI->load->model() 时会报错?
CodeIgniter 3 的 $this->load->model() 是简单 require + new,不经过服务容器。当你在 myClassA2 里执行 $CI->load->model("myClassA1"),框架底层实际做了 new myClassA1() ——而 myClassA1 的 __construct() 是 protected,外部调用非法,PHP 立即抛出 Fatal Error。
- 这不是 CI 的 bug,是 PHP 访问控制的硬性限制
- 解决方向只有两个:把
myClassA1::__construct()改成public,或者彻底弃用load->model(),改用服务容器管理生命周期 - 如果坚持用工厂模式(比如只允许通过
MyClassA1::getInstance()获取),那必须自己封装一个服务提供者,在Services.php里返回该实例,再用service('myClassA1')调用
Factory 类和 Service Locator 模式怎么配合用?
CodeIgniter 4 的 ControllerFactory 本身就是一个轻量级服务定位器:它不硬编码依赖,而是根据控制器类名去服务容器里查、解析、组装、返回实例。你不需要自己 new 工厂类,框架已经把它注册为 controller_factory 服务。
- 真正需要你动手的是「往容器里塞什么」:在
app/Config/Services.php里加一个静态方法,比如public static function myClassA1(),里面 return 一个合法实例(绕过protected构造函数) - 不要试图在工厂类外重写
new行为——CI 不允许你替换ControllerFactory的核心逻辑;你能干预的只有服务注册和类型绑定 - 最易忽略的一点:服务容器默认不缓存“每次 new”的服务。如果你的
myClassA1是有状态的,记得在Services.php里加上->setShared(true),否则每次service('myClassA1')都会新建对象

















