PHP 早期數據庫擴展(mysql、oci8、pgsql 等)API 不一致、代碼重複、維護困難。2003 年 LinuxTag 大會上,核心開發者確立 PDO 目標:
| 優勢 | 說明 |
| 性能 | 全新代碼庫,充分利用 PHP 5 特性優化 |
| 能力 | 基礎功能統一 + 驅動層暴露特有功能 |
| 簡單 | API 直觀,不強制侵入業務代碼 |
| 運行時擴展 | 模塊化驅動,無需重編 PHP 即可加載新數據庫支持 |
安裝與配置
Linux/Unix (PECL)
# 安裝 PHP 5 (--prefix=/usr/local/php5)
./configure --prefix=/usr/local/php5 --with-zlib
make install
# 安裝 PDO 核心與 Oracle 驅動
export PATH=/usr/local/php5/bin:$PATH
pear install PDO-alpha
pear install PDO_OCI-alpha
# php.ini 添加
extension=pdo.so
extension=pdo_oci.so
Windows
# 1. 解壓 PHP 5 到 C:\php5
# 2. 下載 php_pdo.dll, php_pdo_oci.dll 到 C:\php5\ext
# 3. php.ini 添加(順序重要!)
extension=php_pdo.dll
extension=php_pdo_oci.dll
# 4. 將 C:\php5 加入系統 PATH
連接 Oracle
<?php
try {
// DSN 格式:驅動名:可選參數
$dbh = new PDO('oci:dbname=ORCL;charset=UTF-8', 'scott', 'tiger');
// 或簡化:$dbh = new PDO('oci:', 'scott', 'tiger'); // 使用默認 TNS
} catch (PDOException $e) {
die('連接失敗: ' . $e->getMessage());
}
?>
連接管理
- 當前版本無連接池,`$dbh = null` 釋放連接
- 未來計劃支持持久連接與預處理語句緩存
- ODBC 驅動可利用 ODBC 連接池
核心操作範例:事務 + 預處理 + 批量導入
<?php
$dbh = new PDO('oci:', 'scott', 'tiger');
// 建表
$dbh->exec('CREATE TABLE CREDITS (extension VARCHAR(255), name VARCHAR(255))');
// 開啟事務
$dbh->beginTransaction();
// 預處理語句
$stmt = $dbh->prepare('INSERT INTO CREDITS (extension, name) VALUES (:ext, :name)');
$stmt->bindParam(':ext', $ext, PDO::PARAM_STR, 64);
$stmt->bindParam(':name', $name, PDO::PARAM_STR, 64);
// CSV 導入
$fp = fopen('credits.csv', 'r');
while (!feof($fp)) {
list($ext, $name) = fgetcsv($fp, 1024);
$stmt->execute();
}
fclose($fp);
// 提交事務
$dbh->commit();
?>
事務處理機制
- 默認自動提交模式
- `beginTransaction()` 關閉自動提交
- `commit()` / `rollBack()` 結束事務並恢復自動提交
- 腳本異常退出或連接釋放時自動回滾未提交事務
多種抓取模式
$stmt = $dbh->prepare('SELECT extension, name FROM CREDITS');
$stmt->execute();
// 數值索引數組
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
printf('Extension %s, by %s<br>', $row[0], $row[1]);
}
// 關聯數組
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "Extension {$row['EXTENSION']} by {$row['NAME']}<br>";
}
// 匿名對象
while ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
echo "Extension {$row->EXTENSION} by {$row->NAME}<br>";
}
// 惰性加載(大結果集節省內存)
while ($row = $stmt->fetch(PDO::FETCH_LAZY)) {
// 只在訪問屬性時才複製該列數據
}
// 綁定輸出列(最高性能,避免創建數組/對象)
$stmt->bindColumn('EXTENSION', $ext);
$stmt->bindColumn('NAME', $name);
while ($stmt->fetch(PDO::FETCH_BOUND)) {
echo "Extension:$ext, Author:$name\n";
}
可移植性處理
- 大小寫規範:`$dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER)` 強制列名大寫
- 統一錯誤碼:`PDO::ERR_NONE`、`PDO::ERR_SYNTAX`、`PDO::ERR_CONSTRAINT` 等
- 錯誤模式:`SILENT`(默認) / `WARNING` / `EXCEPTION`
數據類型與 NULL 處理
- PDO 傾向以字符串返回數據,避免過早類型轉換導致精度損失
- Oracle 將空字符串視為 NULL,其他數據庫不一致
- `$dbh->setAttribute(PDO::ATTR_ORACLE_NULLS, true)` 統一行為:空串→NULL
未來路線圖
- LOB 流式支持(綁定參數傳遞文件/Socket/壓縮流)
- 持久連接 + 預處理語句緩存
- 可滾動游標、REF CURSOR、定位更新
總結
PDO 為 PHP 帶來了企業級數據庫訪問標準。對於 Oracle 開發者,`PDO_OCI` 提供了比 `oci8` 更現代、更面向對象、更可移植的 API。雖然早期版本標記 alpha,但核心功能已穩定可用,建議在新項目中優先採用。
- 上一篇文章: PHP + JavaScript 實現頁面局部數據定時刷新(AJAX 前身技術)
- 下一篇文章: PHP Socket 通訊深度研究:fsockopen vs socket擴展 實戰對比
Copyright ©
程式碼之家 All Rights Reserved