IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    PDOStatement::bindParam的一个陷阱

    Laruence发表于 2012-10-16 15:01:56
    love 0
    • 作者: Laruence( )
    • 本文地址: http://www.laruence.com/2012/10/16/2831.html
    • 转载请注明出处

    废话不多说, 直接看代码:

    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:

     $value ){
        $statement->bindParam($key, $value);
    }
    

    相当于:

    bindParam(":username", &$value); //此时, :username是对$value变量的引用
    
    //第二次循环
    $value = $bind_params[":password"]; //oops! $value被覆盖成了:password的值
    $statement->bindParam(":password", &$value);
    

    所以, 在使用bindParam的时候, 尤其要注意和foreach联合使用的这个陷阱. 那么正确的作法呢?

    1. 不要使用foreach, 而是手动赋值

    bindParam(":username", $bind_params[":username"]); //$value是引用变量了
    $statement->bindParam(":password", $bind_params[":password"]);
    

    2. 使用bindValue代替bindParam, 或者直接在execute中传递整个参数数组.

    3. 使用foreach和reference(不推荐, 原因参看:微博)

     &$value ) { //注意这里
        $statement->bindParam($key, $value);
    }
    

    最后, 展开了说, 对于要求参数是引用, 并且有滞后处理的函数, 都要在使用foreach的时候, 谨慎!


    Comments

    • 2012/10/16, 破月亮 writes: 学习了
    • 2012/10/16, walu writes: 我去。。。这有点离谱
    • 2012/10/16, huangchuan writes: 这个问题真的遇到过。 尤其是想强制指定某参数是整形时,采用foreach,只有第一个sql语句插入的是整形,之后插入的所有sql类型都是字符型
    • 2012/10/16, staryang writes: foreach结束之前, 加上unset($value)就可以了...
    • 2012/10/16, darasion writes: sql 应该必须用单引号吧?
    • 2012/10/17, PDOStatement::bindParam的一个陷阱树林/咖啡 成都专业php网站制作 | 树林/咖啡 成都专业php网站制作 writes: [...] 风雪之隅 » PHP应用 Posted in: php / Tagged: PDOStatementbindParam的一个陷阱 [...]
    • 2012/10/17, 神仙 writes: 设计成是引用型参数是怎么考虑的呢
    • 2012/10/17, JackalHu writes: prepare($sql); $limit = 10; $statement->bindParam(1, $limit); 对LIMIT子句中的占位符,绑定时就需要指定第三个参数为PDO::PARAM_INT。这时直接在execute()中传递整个参数数组,或者foreach就都不好用了
    • 2012/10/17, fifsky writes: 额,我封装的PDO操作类一直都是 foreach ($params as $k => &$param) { $stmt->bindParam($k, $param, PDO::PARAM_STR, strlen($param)); } 这样的,目前还没有发现过问题,看来是个陷阱
    • 2012/10/18, 花生 writes: 学习了,这个果真是个天坑啊
    • 2012/10/23, sleeping fire writes: 的确是个天坑,循环还是好点,用unset可以解决
    • 2012/10/23, 万维网黑客联盟 writes: http://bbs.w3hacker.com nodejs教程 underscore教程 seajs教程 backbone教程
    • 2012/10/23, 芒果互联 writes: 稳定放心的在线服务!互访把 亲
    • 2012/10/23, jmeye writes: 我之前也发现了这个问题,改成这样就好了。 foreach( $bind_params as $key => $value ){ $statement->bindParam($key, $bind_params[$key]); }
    • 2012/10/24, lxylxy888666 writes: 没遇到过,看手册有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); } ?>
    • 2012/10/26, www.cnfnc.com writes: 让萨达姆被捕时被发现他随身携带的除了一把手枪之外还有的就是它的复印件的好帖532170236owpun
    • 2012/10/29, PDOStatement::bindParam的一个陷阱 | 奇言妙事-文学奇谈小小说阅读xlinblog.sinaapp.com writes: [...] 本文地址: http://www.laruence.com/2012/10/16/2831.html [...]
    • 2012/10/31, taylortai writes: 平时很少用这个功能,一般都是几个基本功能
    • 2012/11/02, 轩脉刃 writes: 这个坑真不知道,大坑
    • 2012/11/03, mqg writes: 我们是把值放execute里,这样会有什么问题么
    • 2012/11/07, Anonymous writes: 0
    • 2012/11/16, PHP PDO prepared statement 一则 | 指间世界 writes: [...] 自从用了PDO,代码果然小清新多了,腰也不疼,腿也不酸了,写代码也更有劲了。需要注意的是以上示例里的bindParam如果使用不当即为巨坑,详情见PDOStatement::bindParam的一个陷阱 ,前车之鉴后事之师! This entry was posted in php by love. Bookmark the permalink. [...]
    • 2012/11/16, 刘悦 writes: 很久没有看到鸟哥的新文章了...很期待啊...
    • 2012/11/30, HouRay writes: 记得当年也踏入过这个陷阱。 这里的bindParam参数是引用方式传递的。 这么做的后果就是,绑定的所有值都和foreach里最后一个value的值相等了。 还有在foreach($arr AS $k => &$v)这种用法也是有相当大陷阱的。
    • 2012/12/13, 二话不说 writes: 手册已经有此问题的描述!
    • 2012/12/20, PDOStatement::bindParam的一个陷阱 | 5iphp writes: [...] 2012/10/16, 破月亮 writes: 学习了 [...]
    • 2012/12/21, 夏韵 writes: 花色断尽,无韵千年,只为一生,贪恋一季。月晕涣散,一世流年,水榭楼台,风雨苍白。夏,绿生的季节,富美的季节。花蕾将葳蕤带给整座森林,岚岫将氤氲带给整片大地,盛夏将繁阜带给整个世界,...
    • 2012/12/29, 梦康 writes: 先收藏了,不是经常用,一般都是手动赋值。
    • 2012/12/31, PHP教程:PDOStatement::bindParam的一个陷阱 | PHP爱好者 writes: [...] 转自:http://www.laruence.com/2012/10/16/2831.html [...]
    • 2013/01/03, 一场下在深秋的雨 writes: 一场秋雨,在窗外无声地下着,若不是提醒,它或许就会在不知不觉中成为过去。才打开手中的伞,一阵冷意便袭击着全身。雨点不是很大,也不是很紧密,落在伞上的声音,轻微,有一种柔柔的感觉。雨...
    • 2013/01/04, 一路向南 writes: 为什么要用 $query = <<
    • 2013/01/10, unspace writes: 一直使用 execute($params) 单个的时候也是单个bind,还真没遇到过
    • 2013/01/14, 袖之欢 writes: 我一直使用 $stmt=$pdo->prepare($sql) $stmt->execute($params); 这个有什么弱点吗 而且把 $params 和 execute 放在一起感觉更方便一些
    • 2013/01/19, hellodifa writes: 引用和foreach,想说爱你不容易啊……
    • 2013/01/29, 冰山一点红 writes: 学习了
    • 2013/02/05, netinus writes: 之前遇到过,并且当时没理解和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
    • 2013/02/18, cq writes: 真没这么用过。。
    • 2013/03/02, 渊岳 writes: 从知乎来到这里,好像在新浪微博行关注过你,呵呵。
    • 2013/03/03, PHP PDOStatement:bindParam的一个陷阱 | 小谈博客 writes: [...] (转自风雪之隅:http://www.laruence.com/2012/10/16/2831.html) [...]
    • 2013/03/05, 51爱健康 writes: 算是找到原因了,
    • 2013/03/11, waczx writes: 尊敬的鸟哥您好:您的友情链接博客,有几个都是死链,不是个人博客!
    • 2013/03/19, PDOStatement::bindParam的参数分析 | 朱智超的博客 writes: [...] 大家可以注意到,第二个参数前面有个“&”,这个是引用符号,通过这个方法穿进去的值会是引用的。通常我们会使用foreach进行数组遍历绑定,一不小心就错了,详情就参见 PDOStatement::bindParam的一个陷阱这篇文章。 [...]
    • 2013/04/29, PDOStatement::bindParam的一个陷阱 | 午后小憩 writes: [...] 本文地址: http://www.laruence.com/2012/10/16/2831.html [...]
    • 2013/06/18, 123 writes: 123123213
    • 2013/08/09, Dans notre monde interconnecté grâce aux nouveautés technologiques writes: [...] 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 [...]
    • 2013/08/28, studentUser writes: 用foreach 没有问题的! Will actually end up being double-quoted and can cause problems.
    • 2013/10/09, terry writes: 设计为引用目的是为了提高效率,非引用的传值相当于复制变量,即内存中会多出一份数据。一般来说,在使用bindParam()绑定变量的时候,可以直接使用execute(array(':name'=>'jack'))把数组直接传进去的方式,简单方便。效果一样!
    • 2013/12/10, 瞬间的永恒 writes: 以前随便看了一下,最近在工作中遇到类似问题,重新好好看了一下,总算理解了原因啦
    • 2013/12/30, 找名网 writes: 学习了,不错!
    • 2014/03/13, nikbobo writes: 原来如此。。好吧,MySQLi 不支持此方法。。。。
    • 2014/05/27, kaola writes: 以前确实遇到过这个坑..
    • 2014/09/01, gao writes: 非常感谢分享,解决了我的一个大问题
    • 2014/09/13, get adult toys online writes: 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
    • 2014/10/24, reatang writes: 我一般绑定的话,直接就把关联数组传给execute,也没用给键名加上: 就能操作。这样使用的的安全性没问题么?
    • 2014/12/19, PHP 最佳实践(译)一份简短的关于 PHP 容易混淆知识点的实用指南_Linux运维工程师的技术博客 writes: [...] Laruence:PDOStatement::bindParam 的一个陷阱 [...]
    • 2015/01/08, xiao writes: 确实是个大坑,前几天我也遇到了这种情况,我还循环打印值来看都是true,最后没办法只能在excute中用数组了
    • 2015/02/06, clarence writes: 写foreach来绑定SQL参数的时候,肯定要换bindValue ps: 窃以为php引用类型的参数时不需要加'&',总是会很坑,真搞不懂为啥引用类型的参数为什么加'&'会被废弃

    Copyright © 2010 风雪之隅 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)

    Related Posts:

    • 深入理解PHP原理之foreach


沪ICP备19023445号-2号
友情链接