PHP 操作 MySQL 經歷 `mysql_*`(已移除)、`mysqli`、到 `PDO` 三代演進。現代專案應全面採用 `PDO`,享受參數綁定、異常模式、多資料庫抽象等優勢。本文對比新舊 API,給出標準化操作流程與最佳實踐範本。
<?php
// config.php
return [
'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=mydb;charset=utf8mb4',
'user' => 'app_user',
'pass' => 'StrongPassword',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 真實預備語句
PDO::MYSQL_ATTR_SSL_CA => __DIR__ . '/ssl/ca.pem', // 生產環境
],
];
// db.php - 連線單例
class Database {
private static ?PDO $instance = null;
public static function get(): PDO {
if (self::$instance === null) {
$config = require __DIR__ . '/config.php';
self::$instance = new PDO(
$config['dsn'],
$config['user'],
$config['pass'],
$config['options']
);
}
return self::$instance;
}
}
// 使用範例
$pdo = Database::get();
// 1. 查詢單筆
$stmt = $pdo->prepare("SELECT id, name, email FROM users WHERE id = ?");
$stmt->execute([42]);
$user = $stmt->fetch(); // false 或陣列
$stmt->closeCursor();
// 2. 查詢多筆
$stmt = $pdo->prepare("SELECT * FROM articles WHERE status = ? ORDER BY created_at DESC LIMIT ?");
$stmt->execute(['published', 10]);
$articles = $stmt->fetchAll();
$stmt->closeCursor();
// 3. 新增 (回傳自增 ID)
$pdo->prepare("INSERT INTO logs (message, level) VALUES (?, ?)")
->execute(['User login', 'info']);
$logId = $pdo->lastInsertId();
// 4. 更新/刪除 (受影響行數)
$affected = $pdo->prepare("UPDATE users SET last_login = NOW() WHERE id = ?")
->execute([42])
->rowCount();
// 5. 交易控制
try {
$pdo->beginTransaction();
$pdo->prepare("INSERT INTO orders ...")->execute([...]);
$pdo->prepare("UPDATE inventory SET qty = qty - 1 WHERE sku = ?")->execute([$sku]);
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}
<?php
$mysqli = new mysqli('127.0.0.1', 'user', 'pass', 'mydb', 3306);
if ($mysqli->connect_errno) die("Connect failed: " . $mysqli->connect_error);
$mysqli->set_charset('utf8mb4');
// 準備語句
$stmt = $mysqli->prepare("SELECT name FROM users WHERE id = ?");
$stmt->bind_param('i', $id);
$id = 42;
$stmt->execute();
$stmt->bind_result($name);
$stmt->fetch(); // 逐行
$stmt->close();
$mysqli->close();
| 特性 | PDO | mysqli |
|---|---|---|
| 資料庫抽象 | 支援 12+ 驅動 | 僅 MySQL |
| 參數綁定 | 陣列傳遞、命名佔位符 | `bind_param` 類型字串、位置綁定 |
| 錯誤模式 | 例外 (ERRMODE_EXCEPTION) | 需手動檢查 `errno`/設定 `MYSQLI_REPORT_STRICT` |
| 預備語句 | 預設模擬,可關閉 | 原生預備語句 |
| 結果集走訪 | `fetch()`/`fetchAll()`/`fetchColumn()` | `fetch_assoc()`/`fetch_array()`/`bind_result()` |
| 命名參數 | 支援 `:name` | 不支援 |
| 交易 | `beginTransaction`/`commit`/`rollBack` | `begin_transaction`/`commit`/`rollback` |
PDO 是 PHP 存取 MySQL 的現代標準。掌握「單例連線、參數化查詢、例外錯誤、交易控制、資源釋放」五大核心模式,配合嚴格 SQL 模式與字元集一致性,即能構建安全、高效、可維護的資料存取層。