PHP PDO

PDO (PHP Data Objects) 是 PHP 的資料庫抽象層,提供統一的介面存取不同的資料庫。

建立連接

<?php
$dsn = "mysql:host=localhost;dbname=myapp;charset=utf8mb4";
$username = "root";
$password = "secret";

$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,
];

try {
    $pdo = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    throw new Exception("資料庫連接失敗:" . $e->getMessage());
}
?>

PDO 選項

選項說明
PDO::ATTR_ERRMODE錯誤處理模式
PDO::ATTR_DEFAULT_FETCH_MODE預設的取得模式
PDO::ATTR_EMULATE_PREPARES是否模擬預處理

錯誤模式

<?php
// SILENT - 不報錯(預設)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);

// WARNING - 產生警告
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);

// EXCEPTION - 拋出例外(推薦)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
?>

取得模式

<?php
// FETCH_ASSOC - 關聯陣列
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// ['id' => 1, 'name' => 'Alice']

// FETCH_NUM - 數字索引陣列
$user = $stmt->fetch(PDO::FETCH_NUM);
// [0 => 1, 1 => 'Alice']

// FETCH_BOTH - 兩者都有(預設)
$user = $stmt->fetch(PDO::FETCH_BOTH);

// FETCH_OBJ - 物件
$user = $stmt->fetch(PDO::FETCH_OBJ);
// $user->name

// FETCH_CLASS - 指定類別
$stmt->setFetchMode(PDO::FETCH_CLASS, 'User');
$user = $stmt->fetch();
?>

預處理語句

<?php
// 準備語句
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");

// 執行
$stmt->execute([1]);

// 取得結果
$user = $stmt->fetch();

// 命名參數
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute(['email' => 'alice@example.com']);
?>

綁定參數

<?php
$stmt = $pdo->prepare("INSERT INTO users (name, age) VALUES (:name, :age)");

// bindValue - 綁定值
$stmt->bindValue(':name', 'Alice');
$stmt->bindValue(':age', 25, PDO::PARAM_INT);
$stmt->execute();

// bindParam - 綁定變數參考
$name = 'Bob';
$age = 30;
$stmt->bindParam(':name', $name);
$stmt->bindParam(':age', $age, PDO::PARAM_INT);
$stmt->execute();
?>

取得多筆資料

<?php
$stmt = $pdo->query("SELECT * FROM users");

// fetchAll - 取得所有
$users = $stmt->fetchAll();

// 迭代取得
while ($user = $stmt->fetch()) {
    echo $user['name'];
}

// 取得單一欄位
$stmt = $pdo->query("SELECT name FROM users");
$names = $stmt->fetchAll(PDO::FETCH_COLUMN);
// ['Alice', 'Bob', 'Charlie']

// 取得鍵值對
$stmt = $pdo->query("SELECT id, name FROM users");
$users = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
// [1 => 'Alice', 2 => 'Bob']
?>

交易處理

<?php
try {
    $pdo->beginTransaction();
    
    $stmt1 = $pdo->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
    $stmt1->execute([100, 1]);
    
    $stmt2 = $pdo->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
    $stmt2->execute([100, 2]);
    
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}
?>

實用方法

<?php
// 取得最後插入的 ID
$id = $pdo->lastInsertId();

// 取得影響的列數
$count = $stmt->rowCount();

// 取得欄位數
$count = $stmt->columnCount();

// 取得錯誤資訊
$error = $stmt->errorInfo();

// 引用字串(不建議,請用預處理)
$quoted = $pdo->quote("O'Reilly");
?>