專案從 PHP 5.1 遷移至 5.2 時,PDO 預處理語句出現行為差異,導致部分查詢失效。本文實測五種場景並總結最佳實務。
$dsn = 'mysql:host=localhost;dbname=test';
$user = 'monty'; $pass = '0818';
$dbh = new PDO($dsn, $user, $pass);
| 場景 | SQL 片段 | 綁定方式 | PHP 5.1 | PHP 5.2 | 結論 |
|---|---|---|---|---|---|
1. 命名參數 :name | WHERE name=:name | bindParam(':name', $val) 或 bindParam('name', $val) | ✅ 正常 | ✅ 正常 | 兩版本均支援帶/不帶冒號 |
2. 位置參數 ? + 數字索引 | WHERE name=? LIMIT 2 | bindParam(1, $val)(索引從 1 開始) | ✅ 正常 | ❌ HY093: Invalid parameter number | 5.2 不支援命名參數混用位置綁定 |
3. 命名參數用於 LIMIT :page | LIMIT :page | bindParam(':page', $val) | ⏳ 執行卡住 | ✅ 正常 | 5.1 無法在 LIMIT 使用命名參數 |
4. 位置參數用於 LIMIT ? | LIMIT ? | bindParam(1, $val) | ✅ 正常 | ✅ 正常 | 最相容寫法 |
5. ORDER BY / GROUP BY 綁定 | ORDER BY ? | 位置/命名參數 | ⚠️ 不排序 | ❌ 無結果 | 所有版本均不支援識別欄位名綁定 |
LIMIT :param 會導致無限等待。LIMIT :param 修正為正常;ORDER BY/GROUP BY 綁定失效。? 位置參數,要么全部用 :name 命名參數,切勿混用。$sql = "SELECT * FROM t WHERE name=? ORDER BY " . $allowedColumns[$sort] . " LIMIT ?, ?";bindValue($pos, $val, PDO::PARAM_INT) 明確指定型別,避免字串導致查詢計畫異常。scp -P 9888 test_pdo.php rentao@192.168.10.4:/home/rentao/
測試基於 PDO MySQL 驅動,其他驅動(PostgreSQL、SQLite)行為可能不同,請實測確認。