【问题标题】:PDO::ERRMODE_EXCEPTION doesn't suppress warningPDO::ERRMODE_EXCEPTION 不会抑制警告
【发布时间】:2018-02-08 10:01:07
【问题描述】:

http://php.net/manual/en/pdo.error-handling.php

PDO::ERRMODE_WARNING

除了设置错误代码,PDO 还会发出传统的 E_WARNING 消息。如果您只想在不中断应用程序流程的情况下查看发生了什么问题,此设置在调试/测试期间很有用。

PDO::ERRMODE_EXCEPTION

除了设置错误代码,PDO 还会抛出一个 PDOException 并设置其属性来反映错误代码和错误信息。此设置在调试期间也很有用,因为它会在错误点有效地“炸毁”脚本,非常迅速地指出代码中潜在的问题区域(请记住:如果异常导致事务自动回滚脚本终止)。

异常模式也很有用,因为您可以比使用传统 PHP 样式的警告更清晰地构建错误处理,并且与在静默模式下运行并显式检查每个数据库调用的返回值相比,代码/嵌套更少。

但是,代码:

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', '***');
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$connection->query('SET wait_timeout=1;');
sleep(2);

try {
    $connection->query('SELECT 1;');
} catch (\Exception $e) {
    echo sprintf('Caught %s exception: %s', get_class($e), $e->getMessage()) . PHP_EOL;
}

触发警告:

PHP Warning:  PDO::query(): MySQL server has gone away in pdo.php on line 13
PHP Warning:  PDO::query(): Error reading result set's header in pdo.php on line 13
Caught PDOException exception: SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

重要提示:问题不是关于 MySQL 服务器的问题,而是关于 PDO 错误处理。

更新:在所有三种模式下触发的警告:ERRMODE_SILENT、ERRMODE_WARNING、ERRMODE_EXCEPTION

PHP 7.2.1 (cli) (built: Jan  5 2018 17:34:14) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2017 Zend Technologies

【问题讨论】:

  • @B001 他不是在问如何解决错误 2006(请注意,共享代码的唯一目的正是为了触发该错误),而是如何防止 PDO 抛出一个异常一个警告。
  • (这 11 行代码中的哪一行恰好是第 13 行?)你引用的只是说它是处理错误的更好选择,但我不认为它会抑制这也可能导致 PHP 警告。
  • 这是第二个查询的行:$connection->query('SELECT 1;');
  • @CBroe,确实,文档没有说关于抑制,但显然 ERRMODE_WARNING 给人的印象是,警告应该只在该模式下触发。顺便说一句,ERRMODE_SILENT 仍然会触发警告
  • 也许这只是一个疏忽。 C 代码库需要支持三种错误处理模式,我认为这需要在任何地方显式编码。肯定有像这样的边缘情况没有被完全覆盖。

标签: php mysql pdo


【解决方案1】:

我敢说这是一个错误。我找到了两张相关的票:

  • Bug #63812:无论错误处理策略如何,PDO 都会触发警告,于 2012 年为 PHP/5.3.19 提交
  • Bug #74401:PDO 触发警告已设置抛出异常,于 2017 年为 PHP/7.0.17 提交

无论如何,它们仍然是开放的,它们是否是有效的问题并不完全清楚(尽管我怀疑它们是)。这似乎不是一个设计决定,因为其他 MySQL 错误不会同时触发警告和异常:

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'test', 'test',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]);
$connection->query('SELECT * FROM foo');

警告:PDO::query(): SQLSTATE[42S02]: 未找到基表或视图:1146 表“test.foo”不存在

$connection = new PDO('mysql:host=127.0.0.1;dbname=test', 'test', 'test',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$connection->query('SELECT * FROM foo');

致命错误:未捕获的异常“PDOException”,带有消息“SQLSTATE[42S02]:未找到基表或视图:1146 表“test.foo”不存在”

【讨论】:

    【解决方案2】:

    PDO::ERRMODE_EXCEPTION 的目的不是为了防止 php 警告、通知或类似的事情。
    正如您可以在您自己提供的文档中阅读的那样,它会引发异常,而不是将 mysql 错误静默写入结果中。
    因此,不是您手动检查结果是否有错误(mysql 已消失,您有语法错误...等),而是 PDO 将直接抛出您可以捕获的异常。
    正如您的代码所证明的那样,PDO::ERRMODE_EXCEPTION 正是这样做的。
    您必须区分仍将显示的 php 错误、警告等和将转换为异常而不是保存在结果中的 mysql 错误。

    【讨论】:

    • 我明白了,但还有另一种模式 - PDO::ERRMODE_WARNING,仅此而已,我相信应该触发警告。
    猜你喜欢
    • 2014-12-19
    • 2011-12-28
    • 1970-01-01
    • 2018-07-11
    • 2017-06-10
    • 2011-03-31
    • 2019-10-22
    • 2021-12-27
    相关资源
    最近更新 更多