本文目录一览:
- 1、PHP PDOStatement:bindParam插入数据错误问题分析
- 2、php pdo中PDOStatement 类的bindParam和bindValue方法的区别
- 3、php的PDO类中bindValue和bindParam的区别
PHP PDOStatement:bindParam插入数据错误问题分析
废话不多说,
直接看代码:
复制代码
代码如下:
?php
$dbh
=
new
PDO('mysql:host=localhost;dbname=test',
"test");
$query
=
QUERY
INSERT
INTO
`user`
(`username`,
`password`)
VALUES
(:username,
:password);
QUERY;
$statement
=
$dbh-prepare($query);
$bind_params
=
array(':username'
=
"laruence",
':password'
=
"weibo");
foreach(
$bind_params
as
$key
=
$value
){
$statement-bindParam($key,
$value);
}
$statement-execute();
请问,
最终执行的SQL语句是什么,
上面的代码是否有什么问题?
Okey,
我想大部分同学会认为,
最终执行的SQL是:
INSERT
INTO
`user`
(`username`,
`password`)
VALUES
("laruence",
"weibo");
但是,
可惜的是,
你错了,
最终执行的SQL是:
INSERT
INTO
`user`
(`username`,
`password`)
VALUES
("weibo",
"weibo");
是不是很大的一个坑呢?
这个问题,
来自今天的一个Bug报告:
#63281
究其原因,
也就是bindParam和bindValue的不同之处,
bindParam要求第二个参数是一个引用变量(reference).
让我们把上面的代码的foreach拆开,
也就是这个foreach:
复制代码
代码如下:
?php
foreach(
$bind_params
as
$key
=
$value
){
$statement-bindParam($key,
$value);
}
相当于:
复制代码
代码如下:
?php
//第一次循环
$value
=
$bind_params[":username"];
$statement-bindParam(":username",
$value);
//此时,
:username是对$value变量的引用
//第二次循环
$value
=
$bind_params[":password"];
//oops!
$value被覆盖成了:password的值
$statement-bindParam(":password",
$value);
所以,
在使用bindParam的时候,
尤其要注意和foreach联合使用的这个陷阱.
那么正确的作法呢?
1.
不要使用foreach,
而是手动赋值
复制代码
代码如下:
?php
$statement-bindParam(":username",
$bind_params[":username"]);
//$value是引用变量了
$statement-bindParam(":password",
$bind_params[":password"]);
2.
使用bindValue代替bindParam,
或者直接在execute中传递整个参数数组.
3.
使用foreach和reference(不推荐)
复制代码
代码如下:
?php
foreach(
$bind_params
as
$key
=
$value
)
{
//注意这里
$statement-bindParam($key,
$value);
}
最后,
展开了说,
对于要求参数是引用,
并且有滞后处理的函数,
都要在使用foreach的时候,
谨慎!
php pdo中PDOStatement 类的bindParam和bindValue方法的区别
在PDOStatement 类中两种方法的具体说明如下
bool PDOStatement::bindParam ( mixed $parameter , mixed $variable [, int $data_type = PDO::PARAM_STR [, int $length [, mixed $driver_options ]]] )bool PDOStatement::bindValue ( mixed $parameter , mixed $value [, int $data_type = PDO::PARAM_STR ] )-phppdobindparam
区别1:bindParam是绑定一个参数到指定的变量名,bindValue则是把一个值绑定到一个参数
$db = new PDO('mysql:host=localhost;dbname=dbtest;charset=utf8','user','pass');$st = $db-prepare('select * from tabletest where id = ?');$id = 1;$st-bindParam(1,$id,PDO::PARAM_INT);//$st-bindValue(1,$id,PDO::PARAM_INT);-phppdobindparam
在上述代码中,不管是bindParam或者bindValue,都能够正常执行,但是如果换成如下代码$db = new PDO('mysql:host=localhost;dbname=dbtest;charset=utf8','user','pass');$st = $db-prepare('select * from tabletest where id = ?');$st-bindParam(1,1,PDO::PARAM_INT);//$st-bindValue(1,1,PDO::PARAM_INT);-phppdobindparam
bindParam就会报如下错误,但是bindValue却可以正常执行
Fatal error: Cannot pass parameter 2 by reference
总结:bindParam第二个参数有且只能是一个变量名, 不能是一个具体的值,bindValue既可以绑定一个变量名,又可以绑定一个值
区别2:不同于 PDOStatement::bindValue(),PDOStatement::bindParam()中的变量作为引用被绑定,并只在 PDOStatement::execute() 被调用的时候才取其值-phppdobindparam
$db = new PDO('mysql:host=localhost;dbname=dbtest;charset=utf8','user','pass');$st = $db-prepare('select * from tabletest where id = ?');$id = 1;$st-bindParam(1,$id,PDO::PARAM_INT);$id = 2;$st-execute();$rs = $st-fetchAll();print_r($rs);-phppdobindparam
首先给$id赋值为1,bindParam绑定变量,在execute前,更改$id为2,然后进行执行操作,此时获得的结果集是当id=2的时候的查询结果,并非是id为1时的查询结果,这就是变量作为引用的解释,在execute之前,我们可以对此变量进行替换,而执行execute操作时候代入的变量值,是该变量最后一次更改的值。$db = new PDO('mysql:host=localhost;dbname=dbtest;charset=utf8','user','pass');$st = $db-prepare('select * from tabletest where id = ?');$id = 1;$st-bindValue(1,$id,PDO::PARAM_INT);$id = 2;$st-execute();$rs = $st-fetchAll();print_r($rs);-phppdobindparam
而bindValue则不同,在使用bindValue绑定变量后,即使在执行execute之前改变了该变量的值,那么结果也不会变。例如上例中即使我们把$id改为了2,但是最后执行的结果仍然会输出$id
=1时候的结果,因为bindValue绑定的并非是变量的引用,不会随着变量的更改而更改。
虽然两者都能完成sql参数的绑定,但是两者仍然有区别,在实际应用中,我们应该选择适合我们的,下面举一个bindParam使用不当的例子
假设有一个数据表有整形id和字符串型name两个字段,有一数组数据$params = array(1,'张三')准备使用预处理进行插入,具体代码如下
$db = new PDO('mysql:host=localhost;dbname=dbtest;charset=utf8','user','pass');$st = $db-prepare('insert into tabletest(id,name) values(?,?)');$params = array(1,'张三');foreach($params as $k = $v){ $index = $k + 1; $st-bindParam($index,$v);}$st-execute();-phppdobindparam
正常情况被执行的sql语句应该是insert into tabletest(id,name) values(1,'张三');
其实真正执行的sql语句却是insert into tabletest(id,name) values('男','男');
究其原因就是bindParam中的变量作为了引用被绑定,因此最后每个字段插入的数值都变成了最后一个字段的值,而此时我们使用bindValue就不会出现这种问题了。此例中还有一点需要说明的是如果使用的是问号占位符和索引数组结合,特别需要注意bindValue的参数标识符(该方法的第一个参数),索引数组默认从0开始,而bindValue的参数标识符是以1开始,如果直接套入索引数组的0下标,那么程序就会报错,使用的时候一定需要注意。-phppdobindparam
php的PDO类中bindValue和bindParam的区别
1、bindParam是绑定一个参数到指定的变量名
bindValue则是把一个值绑定到一个参数
2、bindParam第二个参数有且只能是一个变量名, 不能是一个具体的值
bindValue既可以绑定一个变量名,又可以绑定一个值
3、不同于 PDOStatement::bindValue(),PDOStatement::bindParam()中的变量作为引用被绑定,并只在 PDOStatement::execute() 被调用的时候才取其值-phppdobindparam