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 相关文章推荐
两种php调用Java对象的方法
Oct 09 PHP
MySQL连接数超过限制的解决方法
Jul 17 PHP
PHP中基于ts与nts版本- vc6和vc9编译版本的区别详解
Apr 26 PHP
使用PHP破解防盗链图片的一个简单方法
Jun 07 PHP
php从完整文件路径中分离文件目录和文件名的方法
Mar 13 PHP
PHP连接access数据库
Mar 27 PHP
PHP实现多维数组转字符串和多维数组转一维数组的方法
Aug 08 PHP
php生成高清缩略图实例详解
Dec 07 PHP
给WordPress中的留言加上楼层号的PHP代码实例
Dec 14 PHP
详谈PHP中的密码安全性Password Hashing
Feb 04 PHP
PHP获取当前URL路径的处理方法(适用于多条件筛选列表)
Feb 10 PHP
Swoole源码中如何查询Websocket的连接问题详解
Aug 30 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
PHP URL地址获取函数代码(端口等) 推荐
2010/05/15 PHP
探讨PHP调用时间格式的参数详解
2013/06/06 PHP
Symfony2学习笔记之系统路由详解
2016/03/17 PHP
php简单计算年龄的方法(周岁与虚岁)
2016/12/06 PHP
php验证码生成器
2017/05/24 PHP
Thinkphp5 自定义上传文件名的实现方法
2019/07/23 PHP
js 替换
2008/02/19 Javascript
六款帮助你实现惊艳视差滚动效果的jQuery插件
2012/09/14 Javascript
jQuery的控件及事件(输入控件及回车事件)使用示例
2013/07/25 Javascript
深入理解JavaScript系列(44):设计模式之桥接模式详解
2015/03/04 Javascript
jQuery实现页面下拉100像素出现悬浮窗口的方法
2016/09/05 Javascript
Vue的百度地图插件尝试使用
2017/09/06 Javascript
微信小程序下拉刷新界面的实现
2017/09/28 Javascript
小程序从手动埋点到自动埋点的实现方法
2019/01/24 Javascript
js实现掷骰子小游戏
2019/10/24 Javascript
js实现左右轮播图
2020/01/09 Javascript
JavaScript单线程和任务队列原理解析
2020/02/04 Javascript
Express 配置HTML页面访问的实现
2020/11/01 Javascript
Python中__init__和__new__的区别详解
2014/07/09 Python
Python实现字典依据value排序
2016/02/24 Python
高质量Python代码编写的5个优化技巧
2017/11/16 Python
numpy找出array中的最大值,最小值实例
2018/04/03 Python
Python RabbitMQ消息队列实现rpc
2018/05/30 Python
python 统计列表中不同元素的数量方法
2018/06/29 Python
python 实现从高分辨图像上抠取图像块
2020/01/02 Python
TensorFlow实现checkpoint文件转换为pb文件
2020/02/10 Python
Python操作MongoDb数据库流程详解
2020/03/05 Python
快速创建python 虚拟环境
2020/11/28 Python
Python操作PostgreSql数据库的方法(基本的增删改查)
2020/12/29 Python
BONIA官方网站:国际奢侈品牌和皮革专家
2016/11/27 全球购物
车间组长岗位职责
2013/12/20 职场文书
给老婆的搞笑检讨书
2014/01/12 职场文书
语文教育专业求职信
2014/06/28 职场文书
离职证明标准格式
2014/09/15 职场文书
心理健康教育培训研修感言
2015/11/18 职场文书
《三国志》赏析
2019/08/27 职场文书