pre_system钩子中调用get_instance()报错,因该阶段CI核心对象尚未初始化,仅支持PHP环境检测、常量定义等无框架依赖操作;post_controller_constructor因控制器已实例化,可安全获取路由和会话信息用于权限控制;CI 4已移除钩子机制,改用事件系统和中间件。

pre_system 钩子为什么总报 Fatal error: Call to undefined function get_instance()
因为 pre_system 是整个 CodeIgniter 生命周期里最早触发的钩子点,此时框架核心对象(CI_Controller 实例)尚未创建,get_instance() 函数内部依赖的 $CI 全局变量也还没赋值。
这个钩子只适合做极早期、无框架依赖的操作:
- 检查 PHP 版本或扩展是否加载(如
extension_loaded('mbstring')) - 定义全局常量(如
define('ENVIRONMENT', 'production')) - 设置错误报告级别(
error_reporting(E_ALL & ~E_NOTICE)) - 禁止直接访问(
if (!defined('BASEPATH')) exit('No direct script access allowed');)
一旦在 pre_system 里调用 get_instance()、$this->load 或任何 CI 类方法,必然崩溃。这不是配置错,是时机硬限制。
post_controller_constructor 比 pre_controller 更适合权限控制的原因
pre_controller 触发时,控制器类都还没被实例化,$this->CI->router 无法准确获取当前请求的 class/method;而 post_controller_constructor 已完成控制器实例化,路由信息已就位。
你可以安全使用:
-
$this->CI->router->fetch_class()获取控制器名 -
$this->CI->router->fetch_method()获取方法名 -
$this->CI->session->userdata('logged_in')判断登录态
示例判断逻辑可写成:
if ($this->CI->router->fetch_class() === 'admin' && ! $this->CI->session->userdata('logged_in')) {
redirect('login');
}
注意:别在 post_controller 做跳转——输出缓冲可能已开启,redirect() 会抛出 headers already sent 错误。
钩子执行顺序严格按 CI 内核硬编码顺序,不能自定义
CodeIgniter 3.x 的钩子点执行顺序是固定的,由 system/core/CodeIgniter.php 中的代码行决定,比如:
-
pre_system在第 129 行触发 -
pre_controller在第 225 行触发 -
post_controller_constructor在第 295 行触发 -
post_controller在第 347 行触发 -
post_system在第 402 行触发
你无法通过调整 hooks.php 里数组顺序来改变执行先后——$hook 数组只是注册表,实际调用完全由内核控制。多个钩子绑定到同一钩子点(如都设为 post_controller_constructor)时,执行顺序就是它们在 hooks.php 中定义的先后顺序。
CI 4 不支持钩子,别在新项目里踩坑
$config['enable_hooks'] 这个配置项在 CodeIgniter 4 中已被彻底移除,system/core/Hooks.php 也不再存在。CI 4 改用事件系统(Events 类)和中间件(Middleware)替代钩子机制。
如果你正在维护 CI 3.x 项目并打算升级到 CI 4,所有钩子逻辑必须重构成:
- 认证/日志类逻辑 → 改为 Filter 或 Service 类
- 输出修改类逻辑 → 改为 Response filter 或 View cell
- 环境检测类逻辑 → 移入
public/index.php或app/Config/Events.php
最易被忽略的一点:很多团队在 CI 4 项目里仍保留 application/config/hooks.php 并尝试启用钩子,结果是零效果且无任何提示——因为框架压根不读这个文件。










