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 相关文章推荐
在Windows中安装Apache2和PHP4的权威指南
Oct 09 PHP
我用php+mysql写的留言本
Oct 09 PHP
关于shopex同步ucenter的redirect问题,导致script不运行
Apr 10 PHP
php中opendir函数用法实例
Nov 15 PHP
学习php设计模式 php实现原型模式(prototype)
Dec 07 PHP
php mysql实现mysql_select_db选择数据库
Dec 30 PHP
php 静态属性和静态方法区别详解
Apr 09 PHP
Yii 2中的load()和save()示例详解
Aug 03 PHP
PHP文件管理之实现网盘及压缩包的功能操作
Sep 20 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 PHP
laravel-admin select框默认选中的方法
Oct 03 PHP
PHP正则之正向预查与反向预查讲解与实例
Apr 06 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+DBM的同学录程序(1)
2006/10/09 PHP
sphinx增量索引的一个问题
2011/06/14 PHP
php静态文件生成类实例分析
2015/01/03 PHP
对PHP PDO的一些认识小结
2015/01/23 PHP
JavaScript 反科里化 this [译]
2012/09/20 Javascript
javascript中的缓动效果实现程序
2012/12/29 Javascript
Extjs4 消息框去掉关闭按钮(类似Ext.Msg.alert)
2013/04/02 Javascript
js获取下拉列表框中的value和text的值示例代码
2014/01/11 Javascript
Javascript获取表单名称(name)的方法
2015/04/02 Javascript
jQuery实现信息提示框(带有圆角框与动画)效果
2015/08/07 Javascript
JS实现的自定义网页拖动类
2015/11/06 Javascript
手写简单的jQuery雪花飘落效果实例
2018/04/22 jQuery
单页面vue引入百度统计的使用方法示例详解
2018/10/13 Javascript
微信小程序左滑删除功能开发案例详解
2018/11/12 Javascript
JS判断数组是否包含某元素实现方法汇总
2020/06/24 Javascript
vue添加锚点,实现滚动页面时锚点添加相应的class操作
2020/08/10 Javascript
解决vue prop传值default属性如何使用,为何不生效的问题
2020/09/21 Javascript
Python subprocess模块学习总结
2014/03/13 Python
详解Python各大聊天系统的屏蔽脏话功能原理
2016/12/01 Python
Python3.X 线程中信号量的使用方法示例
2017/07/24 Python
基于python实现百度翻译功能
2019/05/09 Python
Python学习笔记之列表和成员运算符及列表相关方法详解
2019/08/22 Python
Python单元测试工具doctest和unittest使用解析
2019/09/02 Python
python 用户交互输入input的4种用法详解
2019/09/24 Python
python函数局部变量、全局变量、递归知识点总结
2019/11/15 Python
基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解
2020/06/08 Python
python实现KNN近邻算法
2020/12/30 Python
Spartoo芬兰:欧洲最大的网上鞋店
2016/08/28 全球购物
JBL英国官网:JBL UK
2018/07/04 全球购物
预备党员入党自我评价范文
2014/03/10 职场文书
销售内勤岗位职责
2014/04/15 职场文书
邮政营业员岗位职责
2015/04/14 职场文书
六五普法心得体会2016
2016/01/21 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书
Oracle笔记
2021/04/05 Oracle
postgresql如何找到表中重复数据的行并删除
2023/05/08 MySQL