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

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

复制代码 代码如下:

<?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的时候, 谨慎!

时间: 2024-11-01 09:38:35

PHP PDOStatement:bindParam插入数据错误问题分析_php技巧的相关文章

php的慢速日志引起的Mysql错误问题分析_php技巧

在我们的项目中,开启PHP的慢速日志(request_slowlog_timeout = 10s)是必选项,并且它也让我们发现了很多坑,解决了很多的性能问题. 昨天由于碰到了一个非常奇怪的问题,让我们不得不关闭PHP慢速日志,问题是什么呢? 问题:执行程序时,会报 2013(Lost connection to MySQL server during query) 分析: 1)在我们的后台程序中,会执行一个循环(>300次),循环中会重复执行一条SQL语句: 2)Nginx的访问日志,程式每次执

PHP中Socket连接及读写数据超时问题分析_php技巧

本文实例讲述了PHP中Socket连接及读写数据超时问题.分享给大家供大家参考,具体如下: 虽然PHP中对fsockopen()方法有连接socket的超时参数,但是没有类似C中的连接成功后对数据的读写超时参数设置.没关系,PHP中对stream提供了一系列的方法以防止超时 stream_set_blocking( $fp , false ) 设置数据流为阻塞模式,以防止数据没读完就退出 如果模式为 false, 给定的 socket 描述符将切换到非块模式, 如果为 true, 则切换到块模式

PHP 批量删除数据的方法分析_php技巧

大家可以参考下面的这篇文章http://www.jb51.net/article/6488.htmSQL:$SQL="delete from `doing` where id in ('1,2,3,4')"; 数据用逗号隔开. 表单: 复制代码 代码如下: <form action="?action=doing" method="post"> <input name="ID_Dele[]" type=&quo

PHP+MySQL之Insert Into数据插入用法分析_php技巧

本文实例讲述了PHP+MySQL之Insert Into数据插入用法.分享给大家供大家参考.具体如下: INSERT INTO 语句用于向数据库表中插入新纪录. 向数据库表插入数据 INSERT INTO 语句用于向数据库表添加新纪录. 语法: INSERT INTO table_name VALUES (value1, value2,....) 您还可以规定希望在其中插入数据的列: INSERT INTO table_name (column1, column2,...) VALUES (va

thinkPHP自动验证、自动添加及表单错误问题分析_php实例

本文实例讲述了thinkPHP自动验证.自动添加及表单错误问题.分享给大家供大家参考,具体如下: 最近再做一个项目,想用thinkphp写验证,结果泪奔了几天.一开始就是令牌错误,后来有什么自动添加无效. 一直在测试,一直在查找,知道发现create()方法原来有两个参数, 第一个参数是大家都知道了数据参数,第二个是隐藏的$type参数,这个参数用来控制什么的呢?? 复制代码 代码如下: //$type = $type?$type!empty($data[$this->getPk()])?sel

PHP中addslashes与mysql_escape_string的区别分析_php技巧

本文实例分析了PHP中addslashes与mysql_escape_string的区别.分享给大家供大家参考,具体如下: 1.在插入数据时两者的意义基本一样.区别只在于addslashes 在magic_quotes_sybase=on时将" '"转换成" ' '" 在magic_quotes_sybase=off时将" '"转换成"\ '" 而mysql_escape_string总是将" '"转换成&

PHP数学运算与数据处理实例分析_php技巧

本文实例讲述了PHP数学运算与数据处理方法.分享给大家供大家参考,具体如下: 一.数值数据类型 PHP中,数字或数值数据以及数学函数的使用很简单.基本来说,要处理两种数据类型:浮点数和整数.浮点数和整数值的内部表示分别是C数据类型double和int.类似于C,PHP中这些数据类型遵循同样的一组规则. PHP是一种松散类型的脚本语言,变量可以根据计算的需求改变数据类型.这就允许引擎动态地完成类型转换.所以,如果计算中包含数值和字符串,字符串会在完成计算之前转换为数值,而数值则会在与字符串连接之前

php中让人头疼的浮点数运算分析_php技巧

本文实例分析了php中让人头疼的浮点数运算.分享给大家供大家参考,具体如下: 在做电商的时候,计算价格是免不了的,然后发现了php的一个坑,口算应该正确的值,php运算出来会跟你不一样 请看下面的代码: $price=69.1; $count=100; $total=$price*$count-6910; echo $total; 你猜一下变量$total的值是多少,运行一下这个代码输出:-9.09494701773E-13 怎么解决这个问题呢? 使用round函数 代码修改成: $price=

关于PHP文件的自动运行方法分析_php技巧

本文实例分析了PHP文件的自动运行方法.分享给大家供大家参考,具体如下: 这里分析两种方法: 第一种方法: a.php文件内容 如下: <?php ini_set("error_log", "c:\php\php_error.log"); error_log("a.php is execute----------",0); ignore_user_abort(); // 后台无阻断运行 set_time_limit(0); // 一直给我运