PDO (PHP Data Objects) 是 PHP 5.1+ 內建的資料庫存取抽象層,支援 12+ 資料庫驅動,提供統一介面、預處理語句防 SQL 注入、事務控制與例外處理。本文從安裝到進階用法完整說明。
; php.ini
extension=pdo
extension=pdo_mysql ; MySQL
extension=pdo_pgsql ; PostgreSQL
extension=pdo_sqlite ; SQLite
extension=pdo_oci ; Oracle
extension=pdo_sqlsrv ; SQL Server (Windows)
; 重啟 PHP-FPM / Apache
<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$pass = 'secret';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 拋出例外
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 預設關聯陣列
PDO::ATTR_EMULATE_PREPARES => false, // 使用原生預處理
PDO::ATTR_PERSISTENT => true, // 長連線(視負載決定)
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4", // 設定編碼
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
error_log('DB Connection Failed: ' . $e->getMessage());
die('資料庫連線失敗');
}
?>
<?php
// 單筆
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$user = $stmt->fetch(); // FETCH_ASSOC
// 多筆
$stmt = $pdo->query('SELECT * FROM articles WHERE status = 1 ORDER BY created_at DESC');
$articles = $stmt->fetchAll();
// 逐行處理大量資料(節省記憶體)
$stmt = $pdo->query('SELECT * FROM logs');
while ($row = $stmt->fetch()) {
processLog($row);
}
?>
<?php
// 新增
$stmt = $pdo->prepare('INSERT INTO users (email, name) VALUES (?, ?)');
$stmt->execute([$email, $name]);
$newId = $pdo->lastInsertId();
// 批次新增(單一事務)
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare('INSERT INTO logs (msg) VALUES (?)');
foreach ($messages as $msg) {
$stmt->execute([$msg]);
}
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
?>
<?php
$pdo->beginTransaction();
try {
$pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
$pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
$pdo->commit();
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
?>
| 方法 | 用途 | 回傳 |
|---|---|---|
query() | 執行 SELECT 等有結果集的 SQL | PDOStatement |
exec() | 執行 INSERT/UPDATE/DDL 等無結果集 SQL | 受影響行數 (int) |
prepare() | 準備預處理語句 | PDOStatement |
lastInsertId() | 取得最後自增 ID | string|int |
beginTransaction() | 啟動事務 | bool |
commit() | 提交事務 | bool |
rollBack() | 回滾事務 | bool |
setAttribute() | 設定屬性 (錯誤模式、預設取回模式等) | bool |
errorCode() / errorInfo() | 取得錯誤代碼/資訊 | string/array |
<?php
$stmt = $pdo->query('SELECT id, name FROM users');
$stmt->setFetchMode(PDO::FETCH_CLASS, 'UserEntity'); // 映射到類別
$stmt->setFetchMode(PDO::FETCH_FUNC, function($id, $name) { return "$id:$name"; }); // 自訂函數
$stmt->setFetchMode(PDO::FETCH_KEY_PAIR); // [id => name, ...]
$stmt->setFetchMode(PDO::FETCH_GROUP); // 依第一欄分組
?>
ERRMODE_EXCEPTION**,所有錯誤拋 PDOException,統一在入口捕獲記錄。<?php
$stmt = $pdo->prepare('SELECT * FROM products WHERE price > :price AND status = :status');
$stmt->bindValue(':price', 100.50, PDO::PARAM_STR); // 價格用 STR 避免浮點精度問題
$stmt->bindValue(':status', 1, PDO::PARAM_INT);
$stmt->execute();
?>
PDO 是現代 PHP 資料庫開發的標準,掌握預處理、事務、錯誤模式,即可寫出安全、可維護、可移植的資料存取層。