原始碼使用已棄用的 mysql_* 函數(PHP 7.0 移除),且缺乏預處理、事務支援、異常處理。本文在保留原有介面風格的基礎上,提供 PDO 版現代化重構,並補充最佳實踐。
class mysql {
private $conn;
function __construct($host,$user,$pwd,$database,$charset){
$this->conn = mysql_connect($host,$user,$pwd);
mysql_select_db($database);
mysql_query('SET NAMES '.$charset);
}
function query($sql){ return mysql_query($sql); }
function getRow($sql){ /* ... */ }
function getAll($sql){ /* ... */ }
function insert_id(){ return mysql_insert_id(); }
function affected_rows(){ return mysql_affected_rows(); }
function close(){ mysql_close($this->conn); }
}
class Database {
private PDO $pdo;
public function __construct(array $config) {
$dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset={$config['charset']}";
$this->pdo = new PDO($dsn, $config['user'], $config['pass'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES {$config['charset']}"
]);
}
// 查詢單行
public function getRow(string $sql, array $params = []): ?array {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetch() ?: null;
}
// 查詢多行
public function getAll(string $sql, array $params = []): array {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll();
}
// 查詢單一值
public function getOne(string $sql, array $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchColumn();
}
// 執行增刪改 (返回影響行數)
public function execute(string $sql, array $params = []): int {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->rowCount();
}
// 取得最後插入 ID
public function lastInsertId(): string {
return $this->pdo->lastInsertId();
}
// 事務支援
public function beginTransaction(): void { $this->pdo->beginTransaction(); }
public function commit(): void { $this->pdo->commit(); }
public function rollBack(): void { $this->pdo->rollBack(); }
// 關閉連線 (PDO 無需顯式關閉,析構自動處理)
public function close(): void { $this->pdo = null; }
}
$db = new Database([
'host' => 'localhost',
'user' => 'root',
'pass' => 'password',
'dbname' => 'myapp',
'charset' => 'utf8mb4'
]);
// 參數化查詢,防 SQL 注入
$user = $db->getRow('SELECT * FROM users WHERE email = ? AND status = ?', [$email, 1]);
$users = $db->getAll('SELECT id, name FROM users WHERE created_at > ? ORDER BY id DESC LIMIT 10', [$since]);
// 寫入操作
$db->execute('INSERT INTO logs (msg, level) VALUES (?, ?)', [$message, 'info']);
$logId = $db->lastInsertId();
// 事務範例
try {
$db->beginTransaction();
$db->execute('UPDATE accounts SET balance = balance - ? WHERE id = ?', [100, 1]);
$db->execute('UPDATE accounts SET balance = balance + ? WHERE id = ?', [100, 2]);
$db->commit();
} catch (Exception $e) {
$db->rollBack();
throw $e;
}
? 佔位符,徹底防注入。ERRMODE_EXCEPTION 讓錯誤自動拋出,避免靜默失敗。FETCH_ASSOC 直接回傳鍵值對,無需額外轉換。EMULATE_PREPARES = false 使用真實預處理,效能更佳。beginTransaction/commit/rollBack。mysql_* 呼叫替換為 Database 實例方法。? 佔位符。insert_id() → lastInsertId()、affected_rows() → execute() 回傳值。close() 呼叫(可保留空實作相容)。拋棄舊 API,擁抱 PDO,讓資料庫操作更安全、更優雅。