根本原因是$ci->db未初始化,需在自定义类中显式调用$ci->load->database()触发加载;ci4已弃用get_instance(),须改用依赖注入或database::connect()。

get_instance() 后调用 $CI->db 报错“Call to a member function query() on null”
根本原因是 get_instance() 返回的超对象虽已存在,但 $CI->db 属性尚未初始化——它依赖 Loader 类在控制器生命周期中自动加载,而自定义类不在该生命周期内,$this->load->database() 从未被执行。
不能指望 $CI->db 像在控制器里那样“自然可用”。必须显式触发数据库加载:
- 在自定义类构造函数中,先调用
$CI->load->database()(不传参则使用 default 组) - 若需指定连接组(如
slave),传入组名:$CI->load->database('slave') - 确保
application/config/database.php中对应组配置完整且可连通,否则load->database()会静默失败(DBDebug关闭时无报错) - 不要在方法里重复
load->database(),它内部有单例保护;但首次必须显式调用
CI3 中 get_instance() 获取的 $CI->db 查询结果为空或报错
常见于从库读取场景:你改了 hostname 为 127.0.0.1 解决了连接问题,但查询仍返回空数组或 mysqli_num_rows() expects parameter 1 to be mysqli_result 错误。
这不是 get_instance() 的问题,而是连接后未正确选择数据库或 SQL 执行失败被忽略:
- 检查
$CI->db->database是否为预期库名,不是则手动切换:$CI->db->db_select('your_db_name') - 执行查询后立即检查
$CI->db->error(),例如:if ($CI->db->error()['code']) { log_message('error', 'DB error: ' . json_encode($CI->db->error())); } - 避免直接用
mysqli_query()混用——CI 的$CI->db是封装对象,混用底层连接会导致状态不一致 - 若用的是从库,确认主从同步延迟未导致查不到刚写入的数据,别误判为 DB 对象失效
CI4 中 get_instance() 已弃用,替代方案必须用服务容器
get_instance() 在 CI4 中完全不存在。试图在 CI4 自定义类中调用它会直接抛出 Fatal error: Uncaught Error: Call to undefined function get_instance()。
CI4 的等效做法是通过依赖注入或服务容器获取实例:
- 在构造函数参数中声明依赖,如
public function __construct(protected Database $db),前提是该类由容器创建(如控制器、过滤器、服务类) - 若类是手动 new 的(如工具类),改用
\Config\Database::connect('default')获取连接实例,而非尝试模拟 CI3 的超对象 - 不要在 CI4 中写
$CI =& get_instance()——代码无法运行,且违背框架设计逻辑 - 如果旧 CI3 项目迁移至 CI4,所有含
get_instance()的自定义库都必须重构成基于容器或显式连接的方式
为什么 $CI =& get_instance() 后 var_dump($CI->db) 显示 NULL?
因为 $CI->db 是延迟加载属性。CI3 中它只在第一次调用 $CI->load->database() 或访问 $CI->db(触发魔术方法 __get)时才实例化。单纯获取超对象不等于加载所有核心类。
最容易被忽略的一点是:CI3 的 Loader 类本身也需通过 $CI->load 访问,而 $CI->load 同样是延迟加载的。所以安全顺序只能是:
$CI =& get_instance();-
$CI->load->database();(触发$CI->load和$CI->db初始化) - 之后才能放心用
$CI->db->query()
跳过第二步就直接用 $CI->db,得到的就是 NULL——这不是 bug,是 CI3 的设计机制。











