【问题标题】:PHP 7 try - catch: unable to catch "Catchable fatal error"PHP 7 try-catch:无法捕获“可捕获的致命错误”
【发布时间】:2017-01-21 00:07:59
【问题描述】:

我正在玩try - catch 块:

<?php
try {
    $str = "http://rejstrik-firem.kurzy.cz/73631604";
    $domOb = new DOMDocument();
    $html = $domOb->loadHTMLFile($str);
    $domOb->preserveWhiteSpace = false; 
    $container = $domOb->getElementById('ormaininfotab');   
    echo $container; // <========= this is intended error which I want catch
} 
catch (Exception $e) {
   echo "Exception" . $e->getMessage() . ". File: " . $e->getFile() . ", line: " . $e->getLine();
} 

catch (Error $e) {
   echo "Error" . $e->getMessage() . ". File: " . $e->getFile() . ", line: " . $e->getLine();
}
?>

我的结果是这样的:

可捕获的致命错误:类 DOMElement 的对象不能 在第 8 行的 /var/www/html/cirkve_ares/test.php 中转换为字符串

为什么这个错误没有被第二次捕获?

【问题讨论】:

  • 好的,没人对 try-catch 感兴趣吗?其实对我来说不是这个错误问题。我正在学习 try-catch 在 PHP 中的工作原理。任何机构都可以解释一下,如何捕捉这种类型的错误?为什么没有捕捉到这个错误。
  • 刚遇到同样的问题,也是无法转换为字符串导致的E_RECOVERABLE_ERROR....

标签: php try-catch


【解决方案1】:

作为user2782001 mentioned,这在PHP 开发人员的眼中不是一个错误。他们甚至指出,这些类型的错误应该被称为“可恢复”:

我们应该摆脱对“可捕获”致命错误(如果它们仍然存在)的任何引用,转而支持“可恢复”致命错误。在这里使用“catchable”会令人困惑,因为它们无法使用 catch 块捕获。

ErrorException manual page 上有一个巧妙的解决方法,将这些“可捕获/可恢复”错误转换为 ErrorException。

<?php
function exception_error_handler($severity, $message, $file, $line) {
    if (!(error_reporting() & $severity)) {
        // This error code is not included in error_reporting
        return;
    }
    throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler("exception_error_handler");
?>

现在您将能够通过以下方式捕获这些错误:

<?php
try {
    // Error code
} catch (Error $e) { // this will catch only Errors 
    echo $e->getMessage();
}
?>

try {
    // Error code
} catch (Throwable $t) { // this will catch both Errors and Exceptions
    echo $t->getMessage();
}
?>

【讨论】:

  • IMO 建议的错误处理程序的一个缺点是它改变了error_reporting 的行为。如果有人稍后出现并尝试将 php.ini 从error_reporting = E_ERROR 更改为也包括通知和警告(以增加日志记录),突然间的通知和警告将引发异常。因此,此处理程序具有发出通知、警告等的效果,有效地停止执行,然后才记录消息并继续执行。也许更好的解决方案是不使用error_reporting,而是使用新的配置值或者只是包装停止执行的错误。
  • 上述问题描述here
  • @xdhmoore 不要担心你提到的情况,只需在“用户错误处理程序”的开头放置一个 IF 条件以在错误级别(第一个参数)时返回 false(因此不会抛出 ErrorException)错误处理程序的)是警告和通知。
  • @Esteban 自从我查看此问题以来已经有很长时间了,但是您的建议是不是每次您想更改日志记录级别时都需要更改错误处理程序,而不是能够更改它们单独的配置文件?
  • @xdhmoore 不,您只需更改 php.ini (error_reporting) 中的日志记录级别,我的意思是,在您的自定义 error_handler 中,当 $errno != warning and notices (不是说 error_reporting() != warning and notices )。最后我想说的是,在 error_handler 中抛出异常是个坏主意。
【解决方案2】:

有人将此作为错误报告给 PHP 的开发人员,他们立即认为这不是错误。 https://bugs.php.net/bug.php?id=72948&edit=3

故意省略了这种情况...(实际上,您可以使用错误处理程序简单地将可恢复的致命转换为异常...)

所以你还是要使用

set_error_handler()

函数,我们都希望将其抛在脑后。 PHP 的开发人员非常擅长从不让你的一天太阳光明媚......

【讨论】:

    【解决方案3】:

    可能有一些致命的错误甚至没有被set_error_handler()\Throwable 捕获。

    下面的实现将捕获在 php 7.1 中测试的 \Throwable 甚至没有捕获的错误。它只应在您的开发环境中实现(只需将其添加到您的开发配置文件中),不应在生产环境中完成。

    实施

    register_shutdown_function(function () {
        $err = error_get_last();
        if (! is_null($err)) {
            print 'Error#'.$err['message'].'<br>';
            print 'Line#'.$err['line'].'<br>';
            print 'File#'.$err['file'].'<br>';
        }
    });
    

    示例错误

    Error# Class Path/To/MyService contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Path/To/MyServiceInterface::add)
    Line# 12
    File# Path/To/MyService.php
    

    【讨论】:

      【解决方案4】:

      根据Manual PHP,它已从 PHP 7.4 开始“修复”,现在它抛出异常:

      字符串转换中现有的可恢复致命错误已转换为错误异常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-30
        • 2013-07-18
        • 1970-01-01
        • 2014-03-22
        • 1970-01-01
        • 2022-12-21
        相关资源
        最近更新 更多