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 執行潛在問題的捕獲和處理。通過合理封裝和調用,可以極大增強系統的健壯性和調試能力。
如果你正在設計或維護一個數據庫驅動類,強烈建議將警告捕獲機制納入其中,並結合日誌或異常機制,使數據庫操作更加透明和安全。