服务容器绑定标量参数必须用闭包延迟求值,控制器构造函数只注入服务、运行时参数放方法签名,helper须为无命名空间的全局函数,重写构造函数必须调用parent::__construct()。

服务容器绑定标量参数时直接 new 类,不写闭包
服务容器无法自动推断字符串、数组、整数等标量值该填什么,比如 FileLogger 构造函数要 $logLevel 和 $filePath,你写 $container->set('FileLogger', new FileLogger('debug', '/tmp/app.log')) 是错的——这行代码在容器注册时就执行了,不是每次获取时新建实例,且无法响应环境变量变化。
- 必须用闭包:
$container->set('FileLogger', function () { return new FileLogger(getenv('LOG_LEVEL') ?: 'info', WRITEPATH . 'logs/app.log'); }); - 闭包里可调用
Services::获取其他服务,但注意避免循环依赖 - 若需单例行为(如日志实例全局复用),用
$container->singleton()替代set()
控制器构造函数里塞运行时参数,比如用户ID或路由ID
CI4 控制器由框架反射创建,只接受已注册的服务类型提示。写 public function __construct($userId) 会触发 Too many arguments to method 致命错误,因为容器根本不知道 $userId 从哪来。
- 构造函数只留服务注入:
public function __construct(Session $session, UserModel $userModel) - 运行时数据(如
/user/123中的123)必须放在方法签名里:public function show(int $id) - 别在构造函数里调用
$this->request->getUri()->getSegment()取路径参数——时机太早,$this->request可能还没准备好
自定义 Helper 误写成类或加命名空间,导致函数找不到
Helper 不是服务,不能注册进容器。它是一组全局函数,PHP 加载后直接可用。写成类或加 namespace,会导致 Call to undefined function App\Controllers\my_helper_func() 错误——PHP 在当前控制器命名空间下找函数,自然找不到。
- 文件必须放在
app/Helpers/下,文件名小写+下划线,如string_helper.php - 内容不能有
class、namespace、use,只写纯函数:function truncate_string(string $text, int $len): string { ... } - 加载方式只能是
helper('string')或在app/Config/Constants.php里预加载
忘记调用 parent::__construct() 导致过滤器失效
控制器继承 Controller,父类构造函数负责初始化请求上下文、启用过滤器、设置安全头等。跳过它,beforeFilter、CSRF 验证、甚至 $this->request 都可能为 null。
- 只要重写了构造函数,第一行必须是
parent::__construct(); - 类型提示的服务会自动注入,但父类初始化逻辑不会自动触发
- 如果只注入服务不调用父构造,
$this->session->set()可能静默失败,没有报错但 session 写不进去











