mysqli::get_warnings 返回一个 mysqli_warning 对象链,包含执行 SQL 语句时的所有警告。使用此函数可以捕获如数据截断、数据类型不匹配、索引失效等非致命问题,便于后续处理。
但直接调用该方法较为繁琐,且需要对返回的链表结构进行遍历,封装成类方法后可以简化调用过程,并统一处理警告信息。
在数据库驱动类中添加一个获取警告信息的公有方法。
该方法调用 mysqli::get_warnings,并遍历警告链表,将所有警告整理成数组或字符串。
提供格式化输出,方便日志记录或显示。
在执行 SQL 操作后主动调用该方法,以捕获潜在问题。
<?php
class DatabaseDriver
{
/** @var mysqli */
protected $mysqli;
public function __construct($host, $user, $password, $dbname, $port = 3306)
{
$this->mysqli = new mysqli($host, $user, $password, $dbname, $port);
if ($this->mysqli->connect_errno) {
throw new Exception("Connect failed: " . $this->mysqli->connect_error);
}
}
/**
* 执行 SQL 查询
*
* @param string $sql
* @return mysqli_result|bool
*/
public function query(string $sql)
{
$result = $this->mysqli->query($sql);
// 查询后可以检查警告
$warnings = $this->getWarnings();
if (!empty($warnings)) {
// 这里可以做日志记录或异常处理
foreach ($warnings as $warning) {
error_log("MySQL Warning [{$warning['errno']}]: {$warning['message']} (SQLSTATE: {$warning['sqlstate']})");
}
}
return $result;
}
/**
* 获取当前连接的所有警告信息
*
* @return array 警告信息数组,每个元素包含 errno, sqlstate, message
*/
public function getWarnings(): array
{
$warnings = [];
$warning = $this->mysqli->get_warnings();
while ($warning) {
$warnings[] = [
'errno' => $warning->errno,
'sqlstate' => $warning->sqlstate,
'message' => $warning->message,
];
$warning = $warning->next;
}
return $warnings;
}
public function close()
{
$this->mysqli->close();
}
}
// 使用示例
$db = new DatabaseDriver('localhost', 'root', 'password', 'testdb');
$db->query("INSERT INTO users (id, name) VALUES (1, 'Alice')");
$db->close();
get_warnings 返回的是当前连接的警告,如果不清理或没有合理使用,可能会重复读取老旧警告。通常可以在执行每条语句后读取并清理警告,也可以在必要时调用 mysqli::clear_warnings()(PHP 8.1+ 支持)清空警告链,防止干扰后续操作。
封装中推荐将警告信息以数组形式返回,调用层可以根据需求决定是记录日志还是抛出异常,增强灵活性。
部分早期 PHP 版本对 get_warnings 支持不完善,封装时应考虑版本兼容,或者使用版本检查回退到其他错误处理方式。
在数据库驱动类中封装 mysqli::get_warnings 不仅提升了代码的复用性,也方便了对 SQL 执行潜在问题的捕获和处理。通过合理封装和调用,可以极大增强系统的健壮性和调试能力。
如果你正在设计或维护一个数据库驱动类,强烈建议将警告捕获机制纳入其中,并结合日志或异常机制,使数据库操作更加透明和安全。