此查询在phpMyAdmin中返回5个结果:
SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5
这会在phpMyAdmin中返回count = 12(这很好,因为有12条记录):
SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT 0,5
在添加两个变量(偏移,显示)之前,此功能正常工作,但是现在它不起作用,打印变量会给我偏移= 0,显示= 5(所以仍然是LIMIT 0,5
)。
function getProducts($offset, $display) {
$sql = "SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT ?,?;";
$data = array((int)$offset, (int)$display);
$rows = dbRowsCount($sql, $data);
logErrors("getProducts(".$offset.",".$display.") returned ".$rows." rows.");
if ($rows > 0) {
dbQuery($sql, $data);
return dbFetchAll();
} else {
return null;
}
}
它不起作用,因为我的dbRowsCount(...)
方法返回空字符串(愚蠢PDOStatement::fetchColumn
),因此我将其更改为返回带有PDO::FETCH_ASSOC
的计数,并返回count = 0。
这是执行行计数的函数:
function dbRowsCount($sql, $data) {
global $db, $query;
$regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
if (preg_match($regex, $sql, $output) > 0) {
$query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
$query->setFetchMode(PDO::FETCH_ASSOC);
if ($data != null) $query->execute($data); else $query->execute();
if (!$query) {
echo "Oops! There was an error: PDOStatement returned false.";
exit;
}
$result = $query->fetch();
return (int)$result["count"];
} else {
logErrors("Regex did not match: ".$sql);
}
return -1;
}
我的错误日志为我提供了该程序的输出:
正则表达式输出:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT?,?;
getProducts(0,5)返回0行。
正如您所看到的,SQL没有格式错误,方法输入变量按预期为0和5。
有谁知道出了什么问题?
根据建议,我确实尝试直接执行查询,并返回正确的结果:
function dbDebugTest() {
global $db;
$stmt = $db->query("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT 0,5;");
$result = $stmt->fetch();
$rows = (int)$result["count"];
logErrors("dbDebugTest() returned rows=".$rows);
}
输出:
> dbDebugTest() returned rows=12
根据另一个建议,我改变了!= null到!== null,我还打印出$ data数组:
logErrors("Data: ".implode(",",$data));
if ($data !== null) $query->execute($data); else $query->execute();
输出:
> Data: 0,5
但是,dbRowsCount($ sql,$ data)仍会为此查询返回0行!
遵循建议实现a custom PDOStatement class允许我在绑定值后输出查询,我发现函数将在$ query-> execute($ data)之后停止,因此输出将不打印,虽然自定义类适用于我的程序中的每个其他查询。
更新的代码:
function dbRowsCount($sql, $data) {
global $db, $query;
$regex = '/^SELECT\s+(?:ALL\s+|DISTINCT\s+)?(?:.*?)\s+FROM\s+(.*)$/is';
if (preg_match($regex, $sql, $output) > 0) {
$query = $db->prepare("SELECT COUNT(*) AS count FROM {$output[1]}");
logErrors("Regex output: "."SELECT COUNT(*) AS count FROM {$output[1]}");
$query->setFetchMode(PDO::FETCH_ASSOC);
logErrors("Data: ".implode(",",$data));
$query->execute($data);
logErrors("queryString:".$query->queryString);
logErrors("_debugQuery():".$query->_debugQuery());
if (!$query) {
echo "Oops! There was an error: PDOStatement returned false.";
exit;
}
$result = $query->fetch();
return (int)$result["count"];
} else {
logErrors("Regex did not match: ".$sql);
}
return -1;
}
输出:
正则表达式输出:SELECT COUNT()AS count FROM tbl_product_category WHERE id =?;
数据:5
queryString:SELECT COUNT()AS count FROM tbl_product_category WHERE id =?;
_debugQuery():SELECT COUNT(*)AS count FROM tbl_product_category WHERE id =?;正则表达式输出:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT?,?;
数据:0,5
//函数已停止且无法输出_debugQuery
由于我无法获得自定义PDOStatement类给我一些输出,我想我会重写getProducts(...)
类来将params与命名占位符绑定。
function getProducts($offset, $display) {
$sql = "SELECT * FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT :offset, :display;";
$data = array(':offset'=>$offset, ':display'=>$display);
$rows = dbRowsCount($sql, $data);
logErrors("getProducts(".$offset.",".$display.") returned ".$rows." rows.");
if ($rows > 0) {
dbQuery($sql, $data);
return dbFetchAll();
} else {
return null;
}
}
输出:
正则表达式输出:SELECT COUNT(*)AS count FROM tbl_product WHERE 1 ORDER BY last_update DESC LIMIT:offset,:display;
数据:0,5
//在$ query->执行($ data)后仍然崩溃,因此logErrors("getProducts(".$offset."...))
未打印出来
此dbDebugTest以前曾在SQL字符串中直接声明限制值0,5。现在我已经更新它以正确绑定参数:
function dbDebugTest($offset, $display) {
logErrors("Beginning dbDebugTest()");
global $db;
$stmt = $db->prepare("SELECT COUNT(*) AS count FROM tbl_product WHERE 1 ORDER BY last_update LIMIT :offset,:display;");
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':display', $display, PDO::PARAM_INT);
if ($stmt->execute()) {
$result = $stmt->fetch();
$rows = (int)$result["count"];
logErrors("dbDebugTest() returned rows=".$rows);
} else {
logErrors("dbDebugTest() failed!");
}
}
该功能崩溃,只输出:
开始dbDebugTest()
根据建议打开错误(默认情况下它们已关闭),我这样做了:
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
这本身就让Update 4的dbDebugTest()工作了!
开始dbDebugTest() dbDebugTest()返回rows = 12
现在我的网络服务器日志中出现了错误:
[warn] mod_fcgid:stderr:PHP致命错误:
带有消息'SQLSTATE [42000]的未捕获异常'PDOException':
语法错误或访问冲突:1064 SQL语法中有错误;
检查与MySQL服务器版本对应的手册,以获得正确的语法 在第1行''附近''0','5''附近 在/home/linweb09/b/example.com-1050548206/user/my_program/database/dal.php:36
第36行引用dbRowsCount(...)
方法,行为$query->execute($data)
。
所以另一种方法getProducts(...)
仍然不起作用,因为它使用这种绑定数据的方法,而params变成''0'和'5''(这是一个错误吗?)。有点烦人,但我必须在我的dal.php中创建一个新方法,以允许自己以更严格的方式绑定params - bindParam
。
特别感谢@ Travesty3和@eggyal的帮助!!非常感谢。
答案 0 :(得分:1)
您正在测试$data
NULL
是否为NULL
,而不是标识符运算符(有关===
值的详细信息,请参阅the PHP manual由各种比较运营商处理)。您需要使用身份测试!==
/ {{1}},否则请致电is_null()
。
如上所述@ Travesty3,要测试数组是否为空,请使用empty()
。
答案 1 :(得分:1)
基于问题中的更新2,执行在execute
语句之后停止,看起来查询失败。查看some PDO documentation后,看起来默认的错误处理设置是PDO :: ERRMODE_SILENT,这会导致您看到的行为。
这很可能是由于LIMIT子句中的数字在作为参数传入时被放入单引号中,如this post中所发生的那样。
该帖子的解决方案是使用bindValue
方法将参数指定为整数。所以你可能不得不做类似的事情。
看起来您应该使用try-catch块执行查询以捕获MySQL错误。
bindValue方法:
if ($data !== null)
{
for ($i=0; $i<count($data); $i++)
$query->bindValue($i+1, $data[$i], PDO::PARAM_INT);
$query->execute($data);
}
else
$query->execute();