PHP Conference Japan 2024

PDOStatement::bindParam

(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.1.0)

PDOStatement::bindParam 將參數繫結至指定的變數名稱

說明

public PDOStatement::bindParam(
    字串|整數 $param,
    混合 &$var,
    整數 $type = PDO::PARAM_STR,
    整數 (int) $maxLength = 0,
    混合 (mixed) $driverOptions = null (空值)
): 布林 (bool)

將 PHP 變數繫結到用於準備語句的 SQL 語句中相對應的命名或問號佔位符。與 PDOStatement::bindValue() 不同,變數是以參考方式繫結的,並且只會在呼叫 PDOStatement::execute() 時進行評估。

大多數參數都是輸入參數,也就是以唯讀方式用於建構查詢的參數(但仍可能根據 type 進行型態轉換)。某些驅動程式支援呼叫儲存程序,這些程序會以輸出參數的形式傳回資料,有些也以輸入/輸出參數的形式傳送資料並更新以接收資料。

參數

param

參數識別符。對於使用命名佔位符的預備語句,這將是 :name 形式的參數名稱。對於使用問號佔位符的預備語句,這將是參數的 1 基索引位置。

var

要繫結到 SQL 語句參數的 PHP 變數名稱。

type

使用 PDO::PARAM_* 常數 的參數的顯式資料類型。要從儲存程序返回 INOUT 參數,請使用位元 OR 運算子設定 type 參數的 PDO::PARAM_INPUT_OUTPUT 位元。

maxLength

資料類型的長度。要指示參數是儲存程序的 OUT 參數,您必須明確設定長度。僅當 type 參數為 PDO::PARAM_INPUT_OUTPUT 時才有意義。

driverOptions

傳回值

成功時傳回 true (真),失敗時傳回 false (假)

錯誤/例外

如果屬性 PDO::ATTR_ERRMODE 設定為 PDO::ERRMODE_WARNING,則會發出級別為 E_WARNING 的錯誤。

如果屬性 PDO::ATTR_ERRMODE 設定為 PDO::ERRMODE_EXCEPTION,則會擲出 PDOException

範例

範例 #1 使用命名佔位符執行預備語句

<?php
/* 透過繫結 PHP 變數來執行預備語句 */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour'
);
$sth->bindParam('calories', $calories, PDO::PARAM_INT);
/* 名稱也可以加上冒號 ":" 作為前綴(可選) */
$sth->bindParam(':colour', $colour, PDO::PARAM_STR);
$sth->execute();
?>

範例 #2 使用問號佔位符執行預備語句

<?php
/* 透過繫結 PHP 變數來執行預備語句 */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < ? AND colour = ?'
);
$sth->bindParam(1, $calories, PDO::PARAM_INT);
$sth->bindParam(2, $colour, PDO::PARAM_STR);
$sth->execute();
?>

範例 #3 使用 INOUT 參數呼叫預存程序

<?php
/* 呼叫具有 INOUT 參數的預存程序 */
$colour = 'red';
$sth = $dbh->prepare('CALL puree_fruit(?)');
$sth->bindParam(1, $colour, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 12);
$sth->execute();
print
"榨成果汁後,顏色為: $colour";
?>

另請參閱

新增註釋

使用者貢獻的註釋 23 則註釋

247
atrandafirc at yahoo dot com
14 年前
我知道這之前已經有人說過了,但我還是要寫個註釋,因為我認為牢記這一點很重要

如果您使用 PDO bindParam 進行帶有 LIKE 條件的搜尋,您不能將百分比符號和引號放在參數佔位符 '%:keyword%' 中。

這是錯誤的
"SELECT * FROM `users` WHERE `firstname` LIKE '%:keyword%'";

正確的解決方案是保持佔位符乾淨,像這樣
"SELECT * FROM `users` WHERE `firstname` LIKE :keyword";

然後將百分比符號新增到儲存關鍵字的 PHP 變數中
$keyword = "%".$keyword."%";

最後,PDO 在執行查詢時會自動新增引號,因此您不必擔心它們。

所以完整的範例如下
<?php
// 取得查詢字串中的關鍵字
$keyword = $_GET['keyword'];
// 準備指令
$sth = $dbh->prepare('SELECT * FROM `users` WHERE `firstname` LIKE :keyword');
// 在關鍵字前後加上百分比符號
$keyword = "%".$keyword."%";
// 綁定參數
$sth->bindParam(':keyword', $keyword, PDO::PARAM_STR);
?>
178
Vili
14 年前
這個方法有效($val 使用傳址方式)
<?php
foreach ($params as $key => &$val) {
$sth->bindParam($key, $val);
}
?>

這個方法會失敗($val 使用傳值方式,因為 bindParam 需要 &$variable)
<?php
foreach ($params as $key => $val) {
$sth->bindParam($key, $val);
}
?>
4
jcastromail at yahoo dot es
2 年前
PHP 8.1 改變了這個方法的運作方式。

現在,第四個參數不能為 null。它可以是 0(對於整數),但不能是 null,否則會引發棄用警告。

舊版
$sth->bindParam('calories', $calories, PDO::PARAM_INT);
新版
$sth->bindParam('calories', $calories, PDO::PARAM_INT,0);
51
Steve M
15 年前
請注意,使用 PDOStatement::bindParam 時,整數值在 PDOStatement::execute() 後會被轉換為字串值。(已使用 MySQL 測試)

這在使用 === 運算子比較值時可能會造成問題。

範例
<?php
$active
= 1;
var_dump($active);
$ps->bindParam(":active", $active, PDO::PARAM_INT);
var_dump($active);
$ps->execute();
var_dump($active);
if (
$active === 1) {
// 在此處執行某些操作
// 注意:這會失敗,因為 $active 現在是 "1"
}
?>

結果
int(1)
int(1)
string(1) "1"
9
pegas1981 at yandex dot ru
10 年前
http://technet.microsoft.com/en-us/library/ff628166(v=sql.105).aspx

當將 null 資料繫結到伺服器資料欄位類型 varbinary、binary 或 varbinary(max) 時,您應該使用 $driver_options 指定二進位編碼 (PDO::SQLSRV_ENCODING_BINARY)。有關編碼常數的更多資訊,請參閱常數。
在 Microsoft Drivers for PHP for SQL Server 2.0 版中加入了對 PDO 的支援。

<?php
$db
= new PDO('sqlsrv:server=SQLSERVERNAME;Database=own_exchange', 'user', 'password');
$sql = "INSERT INTO dbo.files(file_name, file_source) VALUES(:file_name, :file_source)";
$stmt = $db->prepare($sql);
$stmt->bindParam(":file_name", $files->name, PDO::PARAM_STR);
$stmt->bindParam(":file_source", file_get_contents($files->tempName), PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
?>
14
dhammari at q90 dot com
15 年前
關於是否可以將單一值繫結到多個相同的佔位符號似乎有些混淆。例如:

$sql = "SELECT * FROM user WHERE is_admin = :myValue AND is_deleted = :myValue ";

$params = array("myValue" => "0");

一些使用者回報,在 PHP 5.2.0 及更早版本中,嘗試將單一參數繫結到多個佔位符號會產生參數不符錯誤。然而,從 5.2.1 版開始,這似乎可以正常運作。

詳細資訊請參閱錯誤報告 40417
http://bugs.php.net/bug.php?id=40417
8
khkiley at adamsautomation dot com
12 年前
SQL Server 2008 R2

如果這在文件中,我沒有偶然發現它。當使用帶有預存程序的繫結輸出參數時,輸出參數會在「最後一個」資料列集處理「之後」更新。

如果您的預存程序沒有返回任何資料列集(沒有 SELECT 陳述式),那麼您就設定好了,您的輸出參數將在預存程序處理後立即準備就緒。

否則,您需要處理資料列,然後
<?php $stmt->nextRowset(); ?>

一旦為每個返回的資料列集完成此操作,您就可以存取輸出參數。
10
cyrylas at gmail dot com
13 年前
請注意,PDO 會根據目前的語系設定格式化數字。因此,如果語系設定的數字格式與標準不同,則查詢將無法正常運作。

例如:
在波蘭語系設定 (pl_PL) 中,正確的小數點分隔符號是逗號 (「,」),因此是 123,45,而不是 123.45。如果我們嘗試將 123.45 繫結到查詢,我們最終會在查詢中得到逗號。

<?php
setlocale
(LC_ALL, 'pl_PL');
$sth = $dbh->prepare('SELECT name FROM products WHERE price < :price');
$sth->bindParam(':price', 123.45, PDO::PARAM_STR);
$sth->execute();
// 結果:
// SELECT name FROM products WHERE price < '123,45';
?>
7
匿名
18 年前
對於在 LIKE '%...%' 子句的佔位符號上使用 bindParam() 的人,請注意以下程式碼可能無法正常運作


<?php
$q
= "SELECT id, name FROM test WHERE name like '%:foo%'";
$s = "carrot";
$sth = $dbh->prepare($q);
$sth->bindParam(':foo', $s);
$sth->execute();
?>

需要的是類似以下的程式碼

<?php
$s
= "%$s%";
$sth->bindParam(':foo', $s);
?>

這樣應該可以 work。 已經在 mysql 4.1, PHP 5.1.3 上測試過。
6
Mike Robinson
11 年前
請注意,使用 bindParam 時,第二個參數是透過參考傳遞的。這表示如果啟用 E_STRICT,以下程式碼將會產生警告

<?php
$stmt
->bindParam('type', $object->getType());

// 嚴格標準:在 /path/to/file.php 的第 123 行中,只能傳遞變數作為參考
?>

如果第二個參數不是實際的變數,請將 $object->getType(); 的結果設定給一個變數,並在 bindParam 中使用該變數,或者改用 bindValue。
9
Filofox
18 年前
不要嘗試在單個 SQL 陳述式中兩次使用相同的命名參數,例如

<?php
$sql
= 'SELECT * FROM some_table WHERE some_value > :value OR some_value < :value';
$stmt = $dbh->prepare($sql);
$stmt->execute( array( ':value' => 3 ) );
?>

... 這將不會返回任何列,也不會顯示錯誤訊息 -- 您必須對每個參數只使用一次。顯然這是預期行為(根據此錯誤報告:http://bugs.php.net/bug.php?id=33886),因為可移植性問題。
4
jeffwa+php at gmail dot com
17 年前
我在手冊的其他備註中花了很長時間才找到這個,所以我想我會把這個小技巧放在這裡,以幫助將來其他人。

在 MySQL 中使用 LIKE 搜尋以及預備語句時,必須在 bindParam() 語句之前將適當的括號附加到 *值* 上,如下所示

<?php
$dbc
= $GLOBALS['dbc'];
$sql = "SELECT * FROM `tbl_name` WHERE tbl_col LIKE ?";
$stmt = $dbc->prepare($sql);

$value = "%{$value}%";
$stmt->bindParam($i, $value, PDO::PARAM_STR);
?>

嘗試使用
<?php
$stmt
->bindParam($i, "%{$value}%", PDO::PARAM_STR);
?>

將會失敗。
2
geompse at gmail dot com
14 年前
如果您要儲存檔案(或二進位資料),使用 PARAM_LOB(而且試圖用 Oracle 執行此操作),請不要錯過此頁面

https://php.dev.org.tw/manual/en/pdo.lobs.php

您會注意到 PDO-PGSQL 和 PDO-OCI 的工作方式完全不同:參數和行為都不一樣。
3
Ofir Attia
10 年前
/*
pdo 類別連線的方法,您可以自行新增案例並使用它。
*/
class Conn{
....
....
private $stmt;
public function bind($parameter, $value, $var_type = null){
if (is_null($var_type)) {
switch (true) {
case is_bool($value)
$var_type = PDO::PARAM_BOOL;
break;
case is_int($value)
$var_type = PDO::PARAM_INT;
break;
case is_null($value)
$var_type = PDO::PARAM_NULL;
break;
default
$var_type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($parameter, $value, $var_type);
}
2
heather dot begazo at gmail dot com
9 年前
文件中關於 bindParam 的長度參數是這樣說的

「要指示參數是儲存程序的 OUT 參數,您必須明確設定長度。」

對於 db2,我發現設定「INPUT_OUTPUT」參數的長度會導致 varchar 參數作為輸入參數時出現問題。我發現的問題是儲存程序被呼叫,但 varchar 輸入參數在我的儲存程序內被設定為 null,因此儲存程序無法正常工作。

這是我的儲存程序的簽名

CREATE OR REPLACE PROCEDURE MY_SCHEMA_NAME.MY_STORED_PROCEDURE_NAME ( IN RUN_ID INTEGER,IN V_SCHEMA_NAME VARCHAR(128),
OUT out_rc INTEGER, OUT out_err_message VARCHAR(100), OUT out_sqlstate CHAR(5), OUT out_sqlcode INT)

以下是可以運作的 PHP 程式碼

$command = "Call MY_SCHEMA_NAME.MY_STORED_PROCEDURE_NAME (?,?,?,?,?,?,?)";
$stmt = $this->GuestDb->prepare($command);
$stmt->bindParam(1, $RUN_ID, PDO::PARAM_INT);
$stmt->bindParam(2, $V_SCHEMA_NAME, PDO::PARAM_STR);
$stmt->bindParam(3, $V_TABNAME, PDO::PARAM_STR);
$stmt->bindParam(4, $out_rc, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT);
$stmt->bindParam(5, $out_err_message, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT);
$stmt->bindParam(6, $out_sqlstate, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT);
$stmt->bindParam(7, $out_sqlcode, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT);

以下是不會運作的 PHP 程式碼

$command = "Call MY_SCHEMA_NAME.MY_STORED_PROCEDURE_NAME (?,?,?,?,?,?,?)";
$stmt = $this->GuestDb->prepare($command);
$stmt->bindParam(1, $RUN_ID, PDO::PARAM_INT, 12);
$stmt->bindParam(2, $V_SCHEMA_NAME, PDO::PARAM_STR, 128);
$stmt->bindParam(3, $V_TABNAME, PDO::PARAM_STR, 100);
$stmt->bindParam(4, $out_rc, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, 12);
$stmt->bindParam(5, $out_err_message, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 100);
$stmt->bindParam(6, $out_sqlstate, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 6);
$stmt->bindParam(7, $out_sqlcode, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, 12);
3
gilhildebrand at gmail dot com
9 年前
如果命名佔位符號中包含連字號,MySQL 將會回傳錯誤
UPDATE wardrobe SET `T-Shirt`=:T-SHIRT WHERE id=:id

將會回傳以下錯誤:PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number: parameter was not defined' (無效的參數數量:未定義參數)

解決方法:只需從命名佔位符號中移除連字號
UPDATE wardrobe SET `T-Shirt`=:TSHIRT WHERE id=:id
1
Vladimir Kovpak
9 年前
<?php
/**
* 繫結位元值:
*/

$sql = 'SELECT * FROM myTable WHERE level & ?';
$sth = \App::pdo()->prepare($sql);
$sth->bindValue(1, 0b0101, \PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(\PDO::FETCH_ASSOC);
2
flannell
12 年前
我花了一整天都在想這個問題。

試圖使用 INOUT 或 OUT 並使用 XAMPP 上的 Mysql v5.5.16 將回傳變數導入 PHP。

「MySQL 不支援透過其 C API 繫結輸出參數。您必須使用 SQL 層級變數:」

<?php
$stm
= $db->prepare("CALL sp_mysp(:Name, :Email, @sp_result)");

$outputArray = $db->query("select @sp_result")->fetch(PDO::FETCH_ASSOC);
?>

所以在 MySQL 和 PDO 中的「解決方法」是使用兩個 SQL 呼叫。

希望這對某些人有所幫助。
1
Ejaz Ansari
8 年前
給那些對於使用 PDO-bindparam 的插入查詢感到困惑的人

$sql = $db->prepare("INSERT INTO db_fruit (id, type, colour) VALUES (? ,? ,?)");

$sql->bindParam(1, $newId);
$sql->bindParam(2, $name);
$sql->bindParam(3, $colour);
$sql->execute();
0
marco dot marsala at live dot it
1 年前
範例沒有強調這會按預期工作

<?php
/* 透過綁定 PHP 變數來執行預備語句 */
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour'
);
$sth->bindParam('calories', $calories, PDO::PARAM_INT);
/* 名稱也可以加上冒號 ":" 作為前綴(可選) */
$sth->bindParam(':colour', $colour, PDO::PARAM_STR);
$calories = 150;
$colour = 'red';
$sth->execute();
?>

資料庫中的 calories 會被設定為 150,colour 會被設定為 red,因為,正如文件中指出的:「變數會被作為參考綁定,並且只會在呼叫 PDOStatement::execute() 時進行評估。」
0
weronika dot nowak dot code at gmail dot com
2 年前
🧨🧨🧨
<?php
$q
= "SELECT id, name FROM test WHERE name like '%:foo%'";
$s = "carrot";
$sth = $dbh->prepare($q);
$sth->bindParam(':foo', $s);
$sth->execute();
?>

的確,⬆ 這個方法行不通,但你可以使用字串串接 ⬇

<?php
$q
= "SELECT id, name FROM test WHERE name like '%' ||
:foo || '%' "
;
$s = "carrot";
$sth = $dbh->prepare($q);
$sth->bindParam(':foo', $s);
$sth->execute();
?>
0
willie at spenlen dot com
17 年前
如果您使用的是 MySQL 驅動程式,並且有一個帶有 OUT 或 INOUT 參數的預存程序,您目前無法使用 bindValue()。請參閱 http://bugs.php.net/bug.php?id=35935 以取得解決方法。
-2
Tristen Edwin
6 年前
以下是如何在使用者可以提交 n 個關鍵字時,在執行階段建立動態 WHERE LIKE 子句:

<?php

if (array_key_exists('storyPieces', $_POST)) {
$story_pieces = explode(',' $_POST['storyPieces']);
foreach(
$story_pieces as $piece) {
if (
$conditional_count == 0) {
$where_clause .= 'story LIKE ? ';
$conditional_count++;
} else {
$where_clause .= 'AND story LIKE ? ';
$conditional_count++;
}
}
}

// 然後在您準備之後

if (isset($story_pieces)) {
foreach(
$story_pieces as $key => &$piece) {
$piece = "%" . $piece . "%";
$sth->bindParam($key + 1, $piece, PDO::PARAM_STR);
}
}

?>
To Top