概述
近期的项目中,数据访问层类使用了PDO作为底层,PDO相比mysql_*系列函数具有更高的性能和安全性。在使用时却发现了PDO对象处理带有LIMIT子句的SQL语句时,不能正确处理LIMIT子句中的占位符。例如:
$sql = "SELECT * FROM user LIMIT ?, ?";
$stmt = $pdo->prepare($sql);
$stmt->execute(array(0, 20));
....
在这段代码中,按照PDO文档的说法,两个问号的位置将会被0, 20这两个参数填充,并且类型将会使用和参数类型相匹配的PDO数据类型。但是执行这条语句却返回一个空集合。
var_dump($stmt->fetchAll());
// 输出 empty
然而将问号的位置直接填写数字,是可以正常取得20条记录的。
在谷歌上搜索发现,有其他人也遇到了同样的BUG:
http://stackoverflow.com/questions/5508993/pdo-limit-and-offset
http://stackoverflow.com/questions/2269840/php-pdo-bindvalue-in-limit
http://bbs.phpchina.com/thread-149339-1-1.html
关于这一Bug,可以在PHP官方的Bug Report平台找到:
https://bugs.php.net/bug.php?id=44639
解决的方法是,使用bindValue方法绑定值到SQL语句,并且指定第三个参数为INT类型:
$sql = "SELECT * FROM user LIMIT ?, ?";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, 0, PDO::PARAM_INT);
$stmt->bindValue(2, 20, PDO::PARAM_INT);
$stmt->execute();
这样再次执行,发现20条记录被正确地查询出来。
不过这样不算完美解决,我们通常会对PDO对象进行一些封装才使用,比如构建一次查出来SQL语句并返回结果集数组的方法,传参是不能用bindValue的。于是我写了一个用于自动选择类型的函数:
function select_datatype($val) {
if (is_bool($val)) {
return PDO::PARAM_BOOL;
} elseif (is_int($val)) {
return PDO::PARAM_INT;
} elseif {is_null($val)) {
return PDO::PARAM_NULL;
} else {
return PDO::PARAM_STR;
}
}
这样将$stmt->execute(array(0, 20));类似的语句,转换为循环遍历使用bindValue()绑定值,并使用select_datatype()选择类型即可解决这一问题。
其实早在2008年,就有人向PHP官方报告了这个Bug,但是至今仍未被Fix。如果之后有时间,研究研究能不能做个针对这个问题的补丁。
最后
以上就是专一蜻蜓为你收集整理的PHP中PDO数据访问对象处理LIMIT子句的一处BUG的全部内容,希望文章能够帮你解决PHP中PDO数据访问对象处理LIMIT子句的一处BUG所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复