<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $dbh->prepare('INSERT INTO `user` (`username`, `password`) VALUES (:username, :password)');
$params = [':username' => 'laruence', ':password' => 'weibo'];
foreach ($params as $key => $value) {
$stmt->bindParam($key, $value); // 陷阱在此!
}
$stmt->execute();
// 實際執行 SQL:INSERT ... VALUES ('weibo', 'weibo')
預期寫入 laruence、weibo,實際卻寫入兩個 weibo。
bindParam 第二參數必須是變數參考,會在 execute() 時讀取變數當前值。foreach ($arr as $k => $v) 中的 $v 是同一個變數,每次迴圈只是改變其值,導致所有參數綁定指向同一個記憶體位址,最終皆為最後一個值。
<?php
// 等同於:
$value = $params[':username']; // $value = 'laruence'
$stmt->bindParam(':username', $value); // 綁定 $value 參考
$value = $params[':password']; // $value 被覆蓋為 'weibo'
$stmt->bindParam(':password', $value); // 綁定同一個 $value 參考
// execute() 時讀取 $value → 皆為 'weibo'
<?php
$stmt->bindParam(':username', $params[':username']);
$stmt->bindParam(':password', $params[':password']);
// 陣列元素各自為獨立變數,參考互不干擾
<?php
foreach ($params as $key => $value) {
$stmt->bindValue($key, $value); // 綁定「值」而非「參考」
}
// 或直接 execute 陣列
$stmt->execute($params);
bindValue 立即複製值,execute($arr) 內部自動處理,兩者皆避開參考陷阱。
<?php
foreach ($params as $key => &$value) { // 注意 &$value
$stmt->bindParam($key, $value);
}
// 每次迴圈 $value 為陣列元素本身的參考,各自獨立
凡函式要求「參考參數」且「延遲讀取」(如 bindParam、preg_match 第三參數、sort 等),嚴禁在 foreach 值拷貝模式下直接使用迴圈變數。
$stmt->execute($params)$stmt->bindValue($key, $value, PDO::PARAM_INT)bindParam 變數PDO::ATTR_ERRMODE = PDO::ERRMODE_EXCEPTION