- 本文地址: https://www.laruence.com/2012/10/16/2831.html
- 转载请注明出处
废话不多说, 直接看代码:
<?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的时候, 谨慎!
仰慕大名,学习了; http://www.md86.net ,canvas教程
始めて利用させてもらったのですが、対応がとても好感を持てました。支払い方法で、こちらに不備があったのですが、すぐに電話を頂いて商品の到着も指定日の指定時間ちょうどに届きました!!商品も新品Sランクでしたが、本当に美品でここで購入してよかったと満足してます。
スーパーコピー ヴィヴィアン 財布 https://www.88kopi.com
[…] PDO bindParam 要求第二个参数是一个引用变量 […]
绑定可不可以这样写
foreach($param as $k => $v){
$statement->bindParam($k , &$v);
}
这样 还是最后一个 $v 啊!试试就知道了。
[…] Bird brother ~ […]
[…] Bird elder brother’s blog post inside mentioned this problem:http://www.laruence.com/2012/ … […]
谢谢分享
[…] PDO bindParam 要求第二個引數是一個引用變數 […]
[…] PDO bindParam 要求第二个参数是一个引用变量 […]
[…] 本文地址: http://www.laruence.com/2012/10/16/2831.html […]
这个问题,用foreach绑定的时候,写成 foreach( $bind_params as $key => $value ) { //注意这里
$stmt->bindParam($key, $bind_params[$key]);
} 这样貌似就不会出现这个bug了。
HELLO
$statement->bindParam($key, $value);
修改成
$statement->bindParam($key, $bind_params[$key]);
如果插入的都是字符串
这样也可以
foreach( $bind_params as $key => $value ) {
$statement->bindParam($key, trim($value) );
}
使用函数处理可以分配新的地址
正好对这两个函数不解,太及时了,谢谢!
其实这也不算bug,bindParam的初衷就是变量绑定,bindParam()都绑定的一个$value变量可不取值都一样嘛。
在foreach($arr as $k=>$value)里这样写就没问题了
bindParam(’:abc’,$arr[$k])
Si estás comenzando a aprender a tocar guitarra electrica, bien tienes una guitarra acustica, estás en el sitio indicado!
Una gran forma de evaluar que el progreso es para grabar y video a ti mismo a tocar la guitarra.
I’ll immediately snatch your rss as I can’t find your email subscription hyperlink or e-newsletter service.
Do you’ve any? Please let me know in order that I may just subscribe.
Thanks.
For the most part, life is one big trial and error. The only way you’re going to grow is to try new things and the only way to get yourself to try new things is to accept that fact that you’re going to mess up every now and then.
katespade http://www.katespade-outletonline.net/
我今天也遇到这个坑了,查了好久才知道,感谢鸟哥~
[…] http://www.laruence.com/2012/10/16/2831.html […]
写foreach来绑定SQL参数的时候,肯定要换bindValue
ps: 窃以为php引用类型的参数时不需要加’&’,总是会很坑,真搞不懂为啥引用类型的参数为什么加’&’会被废弃
确实是个大坑,前几天我也遇到了这种情况,我还循环打印值来看都是true,最后没办法只能在excute中用数组了
[…] Laruence:PDOStatement::bindParam 的一个陷阱 […]
我一般绑定的话,直接就把关联数组传给execute,也没用给键名加上: 就能操作。这样使用的的安全性没问题么?
Sexy lingerie when sold at wholesale rates is a very lucrative offer for any consumer.
You would undoubtedly enjoy an enhanced charm with its lovely pink
bowknot. The apparel industry in Australia is doing well internationally and the
Aussie made fashion attire is now getting popular
among international fashion freaks.
Feel free to visit my blog post; get adult toys online
非常感谢分享,解决了我的一个大问题
以前确实遇到过这个坑..
原来如此。。好吧,MySQLi 不支持此方法。。。。
学习了,不错!
以前随便看了一下,最近在工作中遇到类似问题,重新好好看了一下,总算理解了原因啦
设计为引用目的是为了提高效率,非引用的传值相当于复制变量,即内存中会多出一份数据。一般来说,在使用bindParam()绑定变量的时候,可以直接使用execute(array(‘:name’=>’jack’))把数组直接传进去的方式,简单方便。效果一样!
用foreach 没有问题的!
Will actually end up being double-quoted and can cause problems.
[…] friday step l' Certaines étusignifiants démontrant united nations effet harmful not fors OGM Au lenenvironnant lesmain l'élection François Hollan durante réalité strain le lieu pour naissance 4492 Ana Salbashan Niveau canal tether […]
123123213
[…] 本文地址: http://www.laruence.com/2012/10/16/2831.html […]
[…] 大家可以注意到,第二个参数前面有个“&”,这个是引用符号,通过这个方法穿进去的值会是引用的。通常我们会使用foreach进行数组遍历绑定,一不小心就错了,详情就参见 PDOStatement::bindParam的一个陷阱这篇文章。 […]
尊敬的鸟哥您好:您的友情链接博客,有几个都是死链,不是个人博客!
算是找到原因了,
[…] (转自风雪之隅:http://www.laruence.com/2012/10/16/2831.html) […]
从知乎来到这里,好像在新浪微博行关注过你,呵呵。
真没这么用过。。
之前遇到过,并且当时没理解和bindValue的区别。
同时其实php官方文档已经有人指出此问题:
comment from php.net
This works ($val by reference):
&$val) {
$sth->bindParam($key, $val);
}
?>
This will fail ($val by value, because bindParam needs &$variable):
$val) {
$sth->bindParam($key, $val);
}
?>
http://www.php.net/manual/en/pdostatement.bindparam.php
学习了
引用和foreach,想说爱你不容易啊……
我一直使用
$stmt=$pdo->prepare($sql)
$stmt->execute($params);
这个有什么弱点吗
而且把 $params 和 execute 放在一起感觉更方便一些
一直使用 execute($params) 单个的时候也是单个bind,还真没遇到过
为什么要用
$query = <<<QUERY
INSERT INTO `user` (`username`, `password`) VALUES (:username, :password);
QUERY;
这样的写法呢?有啥好处?
一场秋雨,在窗外无声地下着,若不是提醒,它或许就会在不知不觉中成为过去。才打开手中的伞,一阵冷意便袭击着全身。雨点不是很大,也不是很紧密,落在伞上的声音,轻微,有一种柔柔的感觉。雨…
[…] 转自:http://www.laruence.com/2012/10/16/2831.html […]
先收藏了,不是经常用,一般都是手动赋值。
花色断尽,无韵千年,只为一生,贪恋一季。月晕涣散,一世流年,水榭楼台,风雨苍白。夏,绿生的季节,富美的季节。花蕾将葳蕤带给整座森林,岚岫将氤氲带给整片大地,盛夏将繁阜带给整个世界,…
[…] 2012/10/16, 破月亮 writes: 学习了 […]
手册已经有此问题的描述!
记得当年也踏入过这个陷阱。
这里的bindParam参数是引用方式传递的。
这么做的后果就是,绑定的所有值都和foreach里最后一个value的值相等了。
还有在foreach($arr AS $k => &$v)这种用法也是有相当大陷阱的。
很久没有看到鸟哥的新文章了…很期待啊…
[…] 自从用了PDO,代码果然小清新多了,腰也不疼,腿也不酸了,写代码也更有劲了。需要注意的是以上示例里的bindParam如果使用不当即为巨坑,详情见PDOStatement::bindParam的一个陷阱 ,前车之鉴后事之师! This entry was posted in php by love. Bookmark the permalink. […]
0
我们是把值放execute里,这样会有什么问题么
这个坑真不知道,大坑
平时很少用这个功能,一般都是几个基本功能
[…] 本文地址: http://www.laruence.com/2012/10/16/2831.html […]
让萨达姆被捕时被发现他随身携带的除了一把手枪之外还有的就是它的复印件的好帖532170236owpun
没遇到过,看手册有demo说明这个问题.
This works ($val by reference):
&$val) {
$sth->bindParam($key, $val);
}
?>
This will fail ($val by value, because bindParam needs &$variable):
$val) {
$sth->bindParam($key, $val);
}
?>
我之前也发现了这个问题,改成这样就好了。
foreach( $bind_params as $key => $value ){ $statement->bindParam($key, $bind_params[$key]);
}
稳定放心的在线服务!互访把 亲
http://bbs.w3hacker.com nodejs教程 underscore教程 seajs教程 backbone教程
的确是个天坑,循环还是好点,用unset可以解决
学习了,这个果真是个天坑啊
额,我封装的PDO操作类一直都是
foreach ($params as $k => &$param)
{
$stmt->bindParam($k, $param, PDO::PARAM_STR, strlen($param));
}
这样的,目前还没有发现过问题,看来是个陷阱
prepare($sql);
$limit = 10;
$statement->bindParam(1, $limit);
对LIMIT子句中的占位符,绑定时就需要指定第三个参数为PDO::PARAM_INT。这时直接在execute()中传递整个参数数组,或者foreach就都不好用了
设计成是引用型参数是怎么考虑的呢
[…] 风雪之隅 » PHP应用 Posted in: php / Tagged: PDOStatementbindParam的一个陷阱 […]
sql 应该必须用单引号吧?
foreach结束之前, 加上unset($value)就可以了…
这个问题真的遇到过。
尤其是想强制指定某参数是整形时,采用foreach,只有第一个sql语句插入的是整形,之后插入的所有sql类型都是字符型
我去。。。这有点离谱
学习了