首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP PDO 類完整指南:連接、查詢、預處理、事務與最佳實踐

     編輯:PHP 相關知識

簡介

PDO (PHP Data Objects) 提供統一的數據庫訪問接口,支援 12 種數據庫驅動,僅支援面向對象 API,是現代 PHP 開發推薦的數據庫訪問方式。

環境檢查

<?php
try {
    $test = new PDO(); // 僅測試類是否存在
    echo "PDO 已安裝";
} catch (Error $e) {
    die("PDO 未安裝,請在 php.ini 啟用 extension=pdo_mysql 等驅動");
}
?>

建立連接

<?php
$dsn = 'mysql:dbname=demo;host=localhost;port=3306;charset=utf8mb4';
$username = 'root';
$password = 'password';

try {
    $db = new PDO($dsn, $username, $password, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // 拋出異常
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 默認關聯數組
        PDO::ATTR_EMULATE_PREPARES => false, // 使用真實預處理
    ]);
} catch (PDOException $e) {
    die('數據庫連接失敗: ' . $e->getMessage());
}
?>

DSN 格式:`驅動:參數1=值1;參數2=值2`。MySQL 必須指定 `charset=utf8mb4` 避免亂碼。

基本查詢

query() - 返回結果集 (SELECT)

<?php
$stmt = $db->query("SELECT * FROM foods WHERE healthy = 0");
$foods = $stmt->fetchAll(); // 獲取所有行

foreach ($foods as $food) {
    echo $food['name'] . "
"; } echo "共 {$stmt->rowCount()} 筆記錄"; // MySQL 支援 rowCount() ?>

exec() - 返回影響行數 (INSERT/UPDATE/DELETE)

<?php
$deleted = $db->exec("DELETE FROM foods WHERE healthy = 1");
echo "刪除 {$deleted} 行";
?>

防注入:quote() 與預處理語句

quote() 字符串轉義

<?php
$input = "this is's' a '''pretty dange'rous str'ing";
$safe = $db->quote($input);
// 結果: 'this is\'s\' a \'\'\'pretty dange\'rous str\'ing'
?>

預處理語句 - 推薦方式

<?php
// 匿名佔位符 ?
$stmt = $db->prepare('SELECT * FROM foods WHERE name = ? AND healthy = ?');
$stmt->execute(['Cake', true]);
$cake = $stmt->fetch();

// 命名佔位符 :name
$stmt2 = $db->prepare('SELECT * FROM foods WHERE name = :name AND healthy = :healthy');
$stmt2->execute([':name' => 'Pie', ':healthy' => false]);
$pie = $stmt2->fetch();

// 批量綁定
$stmt->bindValue(1, 'Cake');
$stmt->bindValue(2, true);
$stmt->execute();

// bindParam 綁定引用 (僅執行時取值)
$name = 'Pie';
$stmt2->bindParam(':name', $name);
$stmt2->execute();
?>

關鍵配置:`PDO::ATTR_EMULATE_PREPARES => false` 強制使用真實預處理,防止某些驅動模擬預處理導致的注入風險。

事務處理

<?php
try {
    $db->beginTransaction();
    
    $db->exec("INSERT INTO orders (user_id, amount) VALUES (1, 100)");
    $db->exec("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1");
    $db->exec("INSERT INTO logs (action) VALUES ('order_created')");
    
    $db->commit();
    echo "事務提交成功";
} catch (Exception $e) {
    $db->rollBack();
    echo "事務回滾: " . $e->getMessage();
}
?>

注意:`rollBack()` 無法回滾 DDL 語句(如 `DROP TABLE`),MySQL 需使用 InnoDB 引擎支援事務。

常用屬性配置

屬性常量說明常用值
ATTR_DEFAULT_FETCH_MODE默認獲取模式FETCH_ASSOC, FETCH_OBJ, FETCH_CLASS
ATTR_ERRMODE錯誤處理模式ERRMODE_EXCEPTION (推薦), ERRMODE_WARNING, ERRMODE_SILENT
ATTR_TIMEOUT查詢超時秒數整數,超時拋出異常
ATTR_EMULATE_PREPARES是否模擬預處理false (推薦使用真實預處理)
ATTR_STRINGIFY_FETCHES數值/布爾轉字符串true/false
ATTR_PERSISTENT持久連接true/false (慎用,可能導致連接泄漏)

進階:獲取模型對象

<?php
class Food {
    public $name;
    public $healthy;
    public function isHealthy() { return (bool)$this->healthy; }
}

$stmt = $db->query('SELECT * FROM foods');
$foods = $stmt->fetchAll(PDO::FETCH_CLASS, 'Food');
// $foods 為 Food 對象數組
foreach ($foods as $food) {
    echo $food->name . ($food->isHealthy() ? ' ✓' : ' ✗') . "
"; } ?>

錯誤處理最佳實踐

<?php
try {
    $stmt = $db->prepare("INSERT INTO users (email) VALUES (?)");
    $stmt->execute([$email]);
} catch (PDOException $e) {
    if ($e->getCode() == 23000) { // 完整性約束違反
        echo "郵箱已存在";
    } else {
        error_log("DB Error: " . $e->getMessage());
        echo "系統繁忙,請稍後重試";
    }
}
?>

總結

PDO 以統一接口、真實預處理支援、靈活獲取模式、異常處理機制,成為 PHP 數據庫訪問的首選。建議:
1. 始終啟用 `ERRMODE_EXCEPTION` 和 `ATTR_EMULATE_PREPARES => false`
2. 優先使用預處理語句
3. 合理使用事務保證數據一致性
4. 根據業務選擇 `FETCH_ASSOC` 或 `FETCH_CLASS`
5. 避免長連接 (`ATTR_PERSISTENT`),改用連接池中間件

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved