PHP错误处理在MySQL和MySQLi中工作,但不能PDO

PHP error handling working in MySQL & MySQLi but not PDO

提问人:Michael Benjamin 提问时间:8/12/2022 最后编辑:Michael Benjamin 更新时间:10/5/2022 访问量:622

问:

我刚刚完成了将一堆 MySQL 和 MySQLi 表单重构为 PDO。

一切似乎都在起作用。

现在开始错误处理。

在MySQL / MySQLi代码中,我一直在使用语句来捕获错误。喜欢这个:if

if (!$database_connection) {    
    // error handling here
}

简单明了。

但是我无法获得类似的设置来使用 PDO。

场景如下:

我有一个数据库的连接,如下所示:

$data_source_name = "mysql:host=$db_host;dbname=$db_name";
$database_connection = new PDO($data_source_name, $db_username, $db_password);

执行如下所示:

$stmt= $database_connection->prepare($sql);
$stmt->execute([$name, $email]);

我正在尝试设置一个如上所述的条件:

if ( database connection fails ) {
   // error handling
}

但是此代码不起作用。

if ( !$database_connection ) {
     // error handling
} else {
    $stmt= $database_connection->prepare($sql);
    $stmt->execute([$name, $email]);
}

此构造适用于 MySQL(现已弃用)和 MySQLi,但不适用于 PDO。if

我最初尝试使用 - 来完成这项工作,正如许多 Stack 帖子中推荐的那样。但经过更多研究,此函数似乎不适用于 PDO 例外trycatch

任何指导和建议表示赞赏。谢谢。

php mysql 错误处理 mysqli pdo

评论

3赞 Bill Karwin 8/12/2022
建议将 prepare() 和 execute() 与参数值一起使用,但 SQL 语句中没有任何参数占位符。您仍在将变量插值到 SQL 字符串中,因此您传递给 execute() 的参数值没有要匹配的参数。我建议您重新阅读有关使用准备好的语句的手册。
0赞 KIKO Software 8/12/2022
创建 PDO 对象时,即使出现错误,也几乎总是会创建该对象。您可以使用以下命令检查错误:PDO::errorInfo。参见:phpdelusions.net/pdo#errors
0赞 Barmar 8/12/2022
如果失败,它将引发异常,您可以使用 . 永远不能返回类的实例以外的任何内容。new PDOtry/catchnew ClassName
2赞 Barmar 8/12/2022
我建议将所有代码包装在 中,并设置 PDO 选项。这样,您就不需要在每次操作后都进行错误检查。try/catchPDO::ATTR_ERRMODE = PDO::ERRMODE_EXCEPTION
0赞 Michael Benjamin 8/12/2022
@Barmar,请参阅我问题中的倒数第二段。这里真的合适吗?try/catch

答:

0赞 Your Common Sense 8/14/2022 #1

这是一个非常常见的谬误,即需要PDO或Mysqli(或任何其他模块)的专用错误处理代码。至少它应该更具体,例如“Mysqli 连接”处理程序,就像您的旧 mysqli 代码一样。

如果你仔细想想,你并不真正关心它是否完全是数据库错误阻止了代码表单的正确执行。也可能有任何其他问题。

诚然,人们很难指望从这样简单的代码中出现任何其他问题,但是,代码可能会增长,变得更加模块化,执行更多任务 - 因此在任何其他部分也会出错。比如,在每个文件中写入数据库凭据有点浪费。因此,很自然地将它们放在一个文件中,然后将其包含在需要数据库交互的所有其他脚本中。因此,此文件可能会损坏,其效果与数据库错误相同。并且也需要修复。

或者,如果您只处理连接错误,则问题也可能在查询执行期间发生(尤其是在您的情况下,因为查询的执行方式即使客户只是输入,它也会出错)。fish'h'chips

您真正关心的是数据是否正确存储(可能也发送了电子邮件),无论可能出现什么故障。这就是我在文章中写这个警告的确切原因,不要将代码的某些特定部分包装在 try-catch 中以报告此特定错误。由于错误报告处理程序必须是整个代码的通用处理程序。

诚然,最简单的异常处理方法是简单地将整个代码包装在一个 try catch 块中,其中必须检查最通用的异常类型,即 。不是很可靠,但最简单。Throwable

这里的关键是包装整个代码,而不仅仅是其中的一些随机部分。但是,不要忘记为PDO设置异常模式,以便在此块中也捕获查询执行错误。

<?php
try {
    require 'pdo.php'
    ...
    $sql = "INSERT INTO other_choices (order,foods) VALUES (?,?)";
    ...
    $stmt= $db_connection->prepare($sql);
    $stmt->execute([$order, $foods]);

    // send emails, etc
} catch (Throwable $e) {
    // do your handling here
}

请注意,我用问号替换了查询中的实际变量,这是使用预准备语句的正确方式,否则这些语句将变得毫无用处,并使您从 mysqli 的所有过渡都徒劳无功(特别是考虑到 mysqli 也支持预准备语句)。

不幸的是,PHP 有两种错误——异常和错误。而 try-catch 只能抓住前者。为了处理各种错误,可以使用错误处理程序。你可以在我关于PHP错误报告的文章中看到一个非常基本的例子。

最后一点:每次网站上发生错误时发送电子邮件并不是最明智的举动。虽然在你的例子中它可能是合理的,因为PHP只在用户提交表单时涉及,但在PHP用于处理每个页面的常规网站上,它可能会导致数千封电子邮件。或者,即使在您的情况下,垃圾邮件发送者也可能以您的表单为目标并发送数千个请求(这本身可能会导致一些溢出错误,因此收件箱中会有数千封电子邮件)。与其手动发送电子邮件,不如考虑使用专用的错误监控软件,例如 Sentry。它只会发送新错误以及汇总的错误信息。

1赞 Barmar 10/1/2022 #2

new PDO如果连接失败,则引发异常。使用异常处理程序:

try {
    $database_connection = new PDO($data_source_name, $db_username, $db_password);
} catch (PDOException $e) {
    // error handling
}