gpt4 book ai didi

php - PDO 不抛出未绑定(bind)参数的异常(并且查询中没有变量)

转载 作者:可可西里 更新时间:2023-11-01 12:55:21 37 4
gpt4 key购买 nike

所以我不知道这里发生了什么

$link = new PDO('pgsql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
$stmt = $link->prepare("SELECT s.*, d.invalid_column FROM students s ORDER BY s.student_id");
$stmt->execute(array(1));
}
catch (PDOException $e) {
print $e->getMessage();
}

当我运行这个小代码示例时,我预计会抛出一个异常(因为 d.invalid_column 不是一个真正的列,我正在传递无法绑定(bind)的参数),但唯一发生的事情是执行返回 false,没有别的。此外,$stmt->errorInfo() 为空,代码为 00000,这使得添加适当的异常抛出变得困难当某些最终用户报告错误时,帮助我跟踪错误。

如果我添加一个 '?'在查询的某处,抛出正确的执行(d.invalid_column 不是有效列),即使我添加了更多不绑定(bind)任何参数的参数。

让这个查询正确出错的方法:
1) 去掉所有参数
2) 添加一个'?'查询

这只是 PDO 中的错误还是什么?

编辑:将引发异常的设置(无效列):

    $stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute(array(1));

$stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute(array(1,2,3));

$stmt = $link->prepare("SELECT s.*, d.invalid_column, ? FROM students s ORDER BY s.student_id");
$stmt->execute();

$stmt = $link->prepare("SELECT s.*, d.invalid_column FROM students s ORDER BY s.student_id");
$stmt->execute();

只有当我的查询中没有 ? 并将某些内容传递给 execute() 时,事情才会悄无声息地失败并且没有来自 PDO 的解释。

最佳答案

当前的 PHP (5.6.13) 可以重现该行为,并且查询甚至不会发送到服务器。

您的案例在 the doc 中有描述作为:

You cannot bind more values than specified; if more keys exist in input_parameters than in the SQL specified in the PDO::prepare(), then the statement will fail and an error is emitted.

期望值 0,给出值 1,语句失败,返回 false。到目前为止,按照记录工作。

您可能会争辩说“发出错误”意味着当 ERRMODE_EXCEPTION 开启时,将抛出异常。这是一个论点,但 PDO 开发人员是否同意这一点并不明显。

更新:

为什么 SQLCode 没有设置?

查看 PDO 源代码,特别是处理 PDO::execute() 的 static PHP_METHOD(PDOStatement, execute),您可以看到所有错误都由宏处理:PDO_HANDLE_STMT_ERR( )

#define PDO_HANDLE_STMT_ERR()   if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }

重点是,当 PDO 不希望有任何参数时传递绑定(bind)参数时,查询永远不会进入 SQL 引擎,因此 SQL 引擎永远没有机会报告伴随 SQLSTATE 的错误

PDO 本身不会创建假的 SQLSTATE,至少在那种情况下不会,所以 stmt->error_code 保持在 PDO_ERR_NONE"00000"

可以理解您希望引发异常,但您应该向 https://bugs.php.net 建议

和MySQL一样吗?

是的,除了使用 MySQL 驱动程序之外,根行为是相同的,prepare 会立即发送到 SQL 引擎,因此如果由于列错误而导致错误,它会更早地失败并带有真正的 SQL 错误。另一方面,PgSQL 驱动程序有一个不同的实现,使其延迟服务器端 prepare。此特定行为在 PHP Postgres PDO driver does not support prepared statement? 中有详细讨论。

无论如何,这里有一个 MySQL 的案例可以证明我的解释,那就是:

  • 查询需要 0 个参数,给出 1 个
  • $stmt->execute 返回 false
  • 没有引发异常
  • PDO::errorCode 是 00000

代码:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
$stmt = $link->prepare("SELECT 1");
$rc=$stmt->execute(array(1));
if ($rc===false)
echo "query failed, errorCode=", $link->errorCode(), "\n";
else
echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
print "A PDOException has occurred";
print $e->getMessage();
}

结果:

query failed, errorCode=00000

在幕后发生的事情是 prepare 被发送到服务器并成功,但是由于参数不匹配,execute 步骤被 PDO 取消。

这是一个不同的例子,因为查询引用了一个不存在的列。我正在添加打印以显示 $stmt->execute 甚至没有被调用,因为异常是由 $stmt->prepare

引发的

代码:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
$stmt = $link->prepare("SELECT nonexisting");
echo "Executing query\n";
$rc=$stmt->execute(array(1));
if ($rc===false)
echo "query failed, errorCode=", $link->errorCode(), "\n";
else
echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
print "A PDOException has occurred";
print $e->getMessage();
}

结果:

A PDOException has occurredSQLSTATE[42S22]: Column not found: 1054 Unknown column 'nonexisting' in 'field list'

请注意“执行查询”步骤从未发生,因为服务器端的准备失败了。

结论

  • 当查询被发送到服务器时,无论是在 prepare() 还是 execute() 中,并且是服务器生成错误,那么我们可以预期会引发 PDOException。

  • 当执行步骤的查询未发送到服务器时,PDO execute() 可能会失败(返回 false)但不会抛出异常并且 errorCode() 停留在 00000

关于php - PDO 不抛出未绑定(bind)参数的异常(并且查询中没有变量),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32789096/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com