【问题标题】:How to avoid PDOStatement::bindParam messing with the referenced value如何避免 PDOStatement::bindParam 与引用值混淆
【发布时间】:2014-02-28 01:39:31
【问题描述】:

我正面临史蒂夫 M 描述的问题,但“大规模”,请参阅http://www.php.net/manual/en/pdostatement.bindparam.php#94711了解详细信息

我正在使用 Phalcon,但它主要用作包装器,问题不能仅限于此。详细问题在这里——https://github.com/phalcon/cphalcon/issues/2111

TL;DR 数组中的 Int 值转换为字符串,如下:

var_dump($params); // array(2) { [0]=> int(6609) [1]=> int(6664) }
$adapter->fetchAll($sql, Db::FETCH_ASSOC, $params);
var_dump($params); // array(2) { [0]=> string(4) "6609" [1]=> string(4) "6664" }

我稍后重用该数组并严重依赖整数。当它们变成字符串时,它会破坏所有的乐趣......无论我用它做什么(将带有 foreach 的值复制到新数组中,array_merge 复制到新数组中,ArrayObject::getArrayCopy 得到一个副本)原始值不断变化(并且值它们被复制的其他数组)。他们唯一可行的复制方法是:

$adapter->fetchAll($sql, Db::FETCH_ASSOC, unserialize(serialize(($params)));

这感觉像是一个巨大的矫枉过正。下面是另一个似乎可行的解决方案,尽管$paramTypes 没有记录(Phalcon code that handles it 供感兴趣的人使用)。

$paramTypes = [];                                                                                                                                               
foreach ($params as $param) {                                                   
    if (is_int($param)) {                                                       
        $paramTypes[] = \PDO::PARAM_INT;                                        
    } else {                                                                    
        $paramTypes[] = null;                                                   
    }                                                                           
}                                                                               
$rows = $this->adapter->fetchAll($sql, Db::FETCH_ASSOC, $params, $paramTypes);  

对我来说,这似乎是最好的方法,但这里是 Axeia 描述的收到负面反馈的相同方法 - http://www.php.net/manual/en/pdo.constants.php#97130

我的问题:

  1. 为什么按照Axeia 建议的方式做这件事可能是个坏主意?
  2. 您能否提出其他替代方案?除了将修改后的数组转换回整数。
  3. WTF???!!!为什么需要引用并修改它?应该有错误报告吗???

非常感谢大家!

【问题讨论】:

  • 用bindValue代替bindParam,原来的变量不会改变。
  • 使用面向对象编程,例如数据传输对象,它不会改变任何东西...
  • 真的。面向对象编程?听起来很有趣,我可能会用谷歌搜索...
  • 如您所见,SO 不适合此类问题。只有那些能够得到“使用 oop”答案的人才会受到社区的欢迎。有人应该运行另一个必须询问编程问题的网站。
  • 为什么人们不阅读手册Phalcon\Db::FETCH_NUM第385页

标签: php mysql pdo phalcon


【解决方案1】:

您的 mysql 数据库将保留数据类型,因为它是宽度 php-mysqlnd 驱动程序,并且这两个属性设置为 false:

$dbh->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$parm1 = 2;
var_dump($parm1);
//  int(2)

$sth = $dbh->prepare('SELECT *  FROM test.table1  WHERE id = ?');
$sth->bindParam(1, $parm1, PDO::PARAM_INT);
$sth->execute();
$data = $sth->fetchAll(PDO::FETCH_ASSOC);
var_dump($parm1);
// int(2)

var_dump($data);

/* you get nice and clean result:
array(1) {
  [0]=>
  array(4) {
    ["id"]=>  int(2)
    ["name"]=>  string(3) "XYZ"
    ["someint"]=>  int(543)
    ["somefloat"]=>   float(1000.0001220703)
  }
}

And table is:
CREATE TABLE `table1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `someint` int(8) DEFAULT NULL,
  `somefloat` float(10,5) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

*/

【讨论】:

  • 感谢您的意见。我已经在 github github.com/phalcon/cphalcon/issues/2111#issuecomment-37133780 上回复了这个问题。你错过了几点。我相信这些属性在保持参数不变方面没有任何作用,明确设置类型 int 确实$sth->bindParam(1, $parm1, PDO::PARAM_INT); - 这是我试图避免手动执行的操作。
【解决方案2】:

问题在于 Phalcon 没有充分使用 PDOStatement::bindParam 而不是 PDOStatement::bindValue。大debate在github上被覆盖,后面跟着pull request,最终已经合并到1.3.2版本中。

【讨论】:

    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    相关资源
    最近更新 更多