PHP PDOStatement:bindParam插入数据错误问题分析


Posted in PHP onNovember 13, 2013

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

<?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 相关文章推荐
一个SQL管理员的web接口
Oct 09 PHP
PHP实现定时生成HTML网站首页实例代码
Nov 20 PHP
PHP求小于1000的所有水仙花数的代码
Jan 10 PHP
PHP分多步骤填写发布信息的简单方法实例代码
Sep 23 PHP
使用PHP导出Word文档的原理和实例
Oct 21 PHP
php解析http获取的json字符串变量总是空白null
Mar 02 PHP
php简单生成一组与多组随机字符串的方法
May 09 PHP
PHP绕过open_basedir限制操作文件的方法
Jun 10 PHP
workerman结合laravel开发在线聊天应用的示例代码
Oct 30 PHP
解决laravel中日志权限莫名变成了root的问题
Oct 17 PHP
Laravel框架实现即点即改功能的方法分析
Oct 31 PHP
PHP用swoole+websocket和redis实现web一对一聊天
Nov 05 PHP
php curl模拟post请求小实例
Nov 13 #PHP
CodeIgniter生成网站sitemap地图的方法
Nov 13 #PHP
php模板原理讲解
Nov 13 #PHP
php构造函数实例讲解
Nov 13 #PHP
PHP将XML转数组过程详解
Nov 13 #PHP
PHP生成sitemap.xml地图函数
Nov 13 #PHP
使用PHP静态变量当缓存的方法
Nov 13 #PHP
You might like
实现 win2003 下 mysql 数据库每天自动备份
2006/12/06 PHP
PHP令牌 Token改进版
2008/07/18 PHP
php Xdebug 调试扩展的安装与使用.
2010/03/13 PHP
将php数组输出html表格的方法
2014/02/24 PHP
浅析PHP程序设计中的MVC编程思想
2014/07/28 PHP
PHP调用.NET的WebService 简单实例
2015/03/27 PHP
jquery创建div 实现代码
2009/04/27 Javascript
JavaScript Timer实现代码
2010/02/17 Javascript
使用CSS和jQuery模拟select并附提交后取得数据的代码
2013/10/18 Javascript
获取非最后一列td值并将title设为该值的方法
2013/10/30 Javascript
js 删除数组的几种方法小结
2014/02/21 Javascript
javascript验证邮件地址和MX记录的方法
2015/06/16 Javascript
基于jQuery实现动态搜索显示功能
2016/05/05 Javascript
jquery过滤特殊字符',防sql注入的实现方法
2016/08/17 Javascript
AngularJs Scope详解及示例代码
2016/09/01 Javascript
jquery+css实现侧边导航栏效果
2017/06/12 jQuery
angular实现input输入监听的示例
2018/08/31 Javascript
关于单文件组件.vue的使用
2018/09/20 Javascript
如何通过setTimeout理解JS运行机制详解
2019/03/23 Javascript
vue中实现拖动调整左右两侧div的宽度的示例代码
2020/07/22 Javascript
JavaScript中遍历的十种方法总结
2020/12/15 Javascript
[01:43]倾听DOTA2英雄之声 魅惑魔女国服配音鉴赏
2013/06/06 DOTA
[01:59]游戏“zheng”当时试玩会
2019/08/21 DOTA
Python中字符串格式化str.format的详细介绍
2017/02/17 Python
python+pyqt实现右下角弹出框
2017/10/26 Python
pygame实现简易飞机大战
2018/09/11 Python
基于Python对数据shape的常见操作详解
2018/12/25 Python
浅谈Python3 numpy.ptp()最大值与最小值的差
2019/08/24 Python
python使用布隆过滤器的实现示例
2020/08/20 Python
几个解决兼容IE6\7\8不支持html5标签的几个方法
2013/01/07 HTML / CSS
德国奢侈品网上商城:Mytheresa
2016/08/24 全球购物
苹果Mac升级:MacSales.com
2017/11/20 全球购物
经典c++面试题三
2015/07/08 面试题
小学数学国培感言
2014/03/10 职场文书
初中军训感想
2015/08/07 职场文书
CSS子盒子水平和垂直居中的五种方法
2022/07/23 HTML / CSS