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 (
    string|int $param,
    mixed &$var,
    int $type = PDO::PARAM_STR,
    int $maxLength = 0,
    mixed $driverOptions = null
): bool

将一个 PHP 变量绑定到 SQL 语句中对应的命名或问号占位符,该占位符用于准备语句。与 PDOStatement::bindValue() 不同,该变量作为引用绑定,并且只会在调用 PDOStatement::execute() 时进行评估。

大多数参数是输入参数,即以只读方式用于构建查询的参数(但仍可能根据 type 进行强制类型转换)。一些驱动程序支持调用返回数据作为输出参数的存储过程,有些还支持作为既发送数据又更新以接收数据的输入/输出参数。

参数

param

参数标识符。对于使用命名占位符的预处理语句,这将是一个 :name 形式的参数名。对于使用问号占位符的预处理语句,这将是参数的 1-indexed 位置。

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 条备注

atrandafirc at yahoo dot com
14 年前
我知道之前已经有人说过这个问题了,但我还是想再写一个备注,因为它很重要。

如果您使用 PDO bindParam 使用 LIKE 条件进行搜索,则不能将百分号和引号放在 param 占位符 '%: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);
?>
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);
}
?>
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);
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"
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();
?>
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
khkiley at adamsautomation dot com
12年前
SQL Server 2008 R2

如果文档中包含此内容,我没有偶然发现它。当将绑定输出参数与存储过程一起使用时,输出参数会在处理完最后一个结果集后更新。

如果您的存储过程不返回任何结果集(没有 SELECT 语句),那么您就可以设置了,您的输出参数将在存储过程处理完毕后立即准备好。

否则,您需要处理行,然后
<?php $stmt->nextRowset(); ?>

完成后,对于每个返回的结果集,您都可以访问输出参数。
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';
?>
Anonymous
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);
?>

这应该可以工作。在 mysql 4.1、PHP 5.1.3 上测试过。
Mike Robinson
11年前
请注意,使用 bindParam 时,第二个参数是按引用传递的。这意味着如果启用了 E_STRICT,则以下内容将产生警告

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

// Strict Standards: Only variables should be passed by reference in /path/to/file.php on line 123
?>

如果第二个参数不是实际变量,请将 $object->getType(); 的结果设置为变量,并在 bindParam 中使用该变量,或者使用 bindValue。
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 ) );
?>

… 这将返回零行且无错误——你必须每个参数只使用一次且仅使用一次。显然这是预期行为(根据这个bug报告:http://bugs.php.net/bug.php?id=33886),因为可移植性问题。
jeffwa+php at gmail dot com
17年前
我花了很长时间才在手册的其它说明中找到这个,所以我认为我应该把这个小技巧放在这里以帮助未来的其他人。

在使用MySQL中的LIKE搜索以及预处理语句时,*value*必须在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);
?>

将会失败。
geompse at gmail dot com
14 年前
如果你正在存储文件(或二进制数据),使用PARAM_LOB(而且尝试使用Oracle),不要错过这个页面

https://php.net/manual/en/pdo.lobs.php

你会注意到PDO-PGSQL和PDO-OCI的工作方式完全不同:参数和行为都不相同。
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);
}
heather dot begazo at gmail dot com
9年前
文档中关于bindParam的长度参数是这样说的

"要指示参数是从存储过程输出的参数,必须显式设置长度。"

对于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);
gilhildebrand at gmail dot com
9年前
如果命名占位符中包含连字符,MySQL将返回错误
UPDATE wardrobe SET `T-Shirt`=:T-SHIRT WHERE id=:id

将返回以下错误:`PDOException`,消息为“SQLSTATE[HY093]: Invalid parameter number: parameter was not defined”

要解决这个问题,只需从命名占位符中删除连字符
UPDATE wardrobe SET `T-Shirt`=:TSHIRT WHERE id=:id
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);
flannell
12年前
整天都在撞墙。

尝试使用INOUT或OUT并将返回值放入PHP中,使用XAMPP上的Mysql v5.5.16。

"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调用。

希望这能帮到某些人。
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();
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()时才会计算。”
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();
?>
willie at spenlen dot com
17年前
如果您使用的是MySQL驱动程序,并且有一个带有OUT或INOUT参数的存储过程,则目前无法使用bindValue()。请参阅http://bugs.php.net/bug.php?id=35935了解解决方法。
Tristen Edwin
6年前
以下是如何在运行时构建动态WHERE LIKE语句,当用户可以提交n个关键字时:

<?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