不能直接在自定义类中调用 $this->load->database(),因为 Loader 仅自动注入到 Controller、Model 和 Library 中,手动 new 的类无此依赖;正确做法是显式传入 $db 实例或通过 get_instance()->db(CI3)/Services::database()(CI4)安全获取。

为什么不能直接在自定义类里用 $this->load->database()
因为 CodeIgniter 的 Loader 类($this->load)默认只注入到 Controller、Model 和 Library 的实例中,而你手动 new 出来的自定义类(比如 class MyService)没有自动获得 $this->load 或 $this->db。直接调用会报 Call to a member function database() on null。
- 不是 CI 版本问题,是对象生命周期和依赖注入机制决定的
- 别在构造函数里硬写
get_instance()—— 它返回的是当前 Controller 实例,但你的类可能在非请求上下文(如 CLI 或队列任务)中运行,此时get_instance()可能未初始化或返回意外对象 - 正确做法是显式传入
$db实例,或通过 CI 的服务定位器(CI_Loader)安全获取
推荐:用 get_instance()->db 但必须加判空和重连逻辑
如果你确认类只在 Web 请求上下文中使用(即已进入 CI 的主流程),可以用 get_instance() 获取全局 CI 实例,再取 db。但必须处理两个关键点:DB 连接是否已初始化、连接是否还活跃。
-
get_instance()返回的是单例 CI 对象,但->db可能为null(比如尚未加载 DB 库) - 即使
$ci->db存在,也可能因超时断开,需调用$ci->db->reconnect()或$ci->db->simple_query('SELECT 1')检测 - 标准写法示例:
$ci = get_instance();
if (!isset($ci->db) || !$ci->db->conn_id) {
$ci->load->database();
}
// 确保连接有效
if (!$ci->db->ping()) {
$ci->db->reconnect();
}
更健壮的做法:把 $db 当构造参数传进来
这是最可控、可测试、符合依赖倒置原则的方式。尤其适合 CLI 命令、定时任务、单元测试等场景。
- 自定义类不耦合 CI 全局状态,便于 mock 和隔离测试
- 避免在类内部调用
get_instance(),消除潜在的“找不到 CI 实例”错误 - Controller 或 Service Factory 中负责准备 DB 实例并注入:
// 在 Controller 中
$this->load->database();
$my_service = new MyService($this->db);
// 自定义类定义
class MyService
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
public function get_user($id)
{
return $this->db->get_where('users', ['id' => $id])->row();
}
}
CI4 注意:完全不兼容 CI3 的 get_instance() 方式
如果你实际用的是 CodeIgniter 4(哪怕文件名还叫 CodeIgniter.php),上面所有基于 get_instance() 的写法都失效。CI4 使用 PSR-4 自动加载 + 服务容器(Services::),DB 必须通过 Services::database() 获取。
- CI4 中没有
get_instance(),强行调用会 fatal error - 正确方式:
$db = \CodeIgniter\Database\Database::connect();或$db = \CodeIgniter\Services::database(); - 注意 CI4 的
database配置分环境(.env或app/Config/Database.php),别漏配default组
混用 CI3/CI4 的项目最容易在这里栽跟头——看到 system/core/CodeIgniter.php 就以为是 CI3,其实可能是 CI4 的兼容层。

















