try...catch仅能捕获Exception及其子类(如RuntimeException),无法捕获E_ERROR、E_PARSE、E_WARNING等传统错误;Fatal error需用register_shutdown_function兜底,但不可恢复执行。

php错误和异常如何处理_trycatch与错误报告设置【详解】

先说一个很多人容易混淆的点:PHP里的错误和异常,根本就是两码事。如果试图用 try...catch 包揽所有报错,那致命错误会直接漏掉,而 E_NOTICE 这类警告它也拦不住。所以必须搞清楚:哪些能捕,哪些得靠错误处理器或配置来管。

哪些错误能被 try...catch 捕获?

try...catch 这个机制,只对 Exception(以及它的子类,比如 RuntimeException)有反应。对于传统意义上的 PHP 错误——比如 E_WARNINGE_NOTICEE_ERROR——它完全无能为力。

很多人会误以为“加了 try 就万事大吉”,但现实很残酷,下面这些情况照样会中断执行,而且 try 根本抓不住:

所以,如果真想用 try...catch 来兜住某段可能出问题的代码,唯一的办法是先把它包装成一个异常,让原本的错误“升级”成异常才行:

function riskyOperation() {    if (!is_readable('/path/to/file')) {        throw new RuntimeException('File not readable');    }    return file_get_contents('/path/to/file');}try {    $data = riskyOperation();} catch (RuntimeException $e) {    // 这里才能捕获到}

如何让传统错误转成异常?

PHP 里有一个利器:set_error_handler()。这个函数可以把大部分运行时错误(除了 E_ERRORE_PARSE 等极少数之外)都转成 ErrorException 的实例,然后就能被 try...catch 优雅地处理了。

这里有几个关键点需要注意:

看个例子:

set_error_handler(function($severity, $message, $file, $line) {    if (!(error_reporting() & $severity)) {        return; // 遵守当前错误报告级别    }    throw new ErrorException($message, 0, $severity, $file, $line);});try {    $x = $undefined_var; // 触发 E_NOTICE} catch (ErrorException $e) {    echo "Caught: " . $e->getMessage();}

error_reportingdisplay_errors 到底管什么?

这两个配置经常被一起关闭,但它们的作用完全不同,是两个独立的开关。

error_reporting 决定的是“哪些错误会被生成”,它是一个生产级别的开关。而 display_errors 决定的是“生成的错误是否直接输出到页面上”,它是一个展示级别的开关。

在生产环境下的典型配置是这样的:

有一点特别值得警惕:error_reporting(0) 不等于“没有错误发生”,而是“不生成任何错误事件”。这意味着连 set_error_handler 都收不到任何通知,所以调试时千万不要这么干,否则问题会像幽灵一样难以追踪。

致命错误(Fatal error)真的无解吗?

对于绝大多数 Fatal error(比如 Call to undefined functionClass not found),确实是无解的。它们无法被 try...catch 捕获,甚至连错误处理器都无能为力,因为 Zend 引擎已经决定要中止脚本了。

唯一能做的“事后补救”方式,就是注册 register_shutdown_function(),并在回调函数里通过 error_get_last() 来检查是否发生了致命错误:

register_shutdown_function(function() {    $error = error_get_last();    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {        // 记录日志、发告警、返回友好提示页        error_log("Fatal: " . $error['message'] . " in " . $error['file'] . ":" . $error['line']);        http_response_code(500);        echo "Service una vailable";    }});

但需要清醒地认识到,这只是一个“兜底”机制,它的作用仅限于事后的记录和友好提示,无法恢复脚本的执行。所以,真正有效的手段,是在部署之前就通过静态分析工具(比如 phpstan)、单元测试、自动加载校验等手段,尽可能把这些致命错误扼杀在摇篮里——这才是治本之道。

本文转载于:https://www.php.cn/faq/2317959.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。