应使用catch (Throwable $e)统一捕获Exception与Error,配合嵌套异常链、全局异常处理器、错误转异常及shutdown钩子,构建全覆盖PHP 7+异常处理体系。

如果您在PHP 7+环境中遇到无法捕获的致命错误(如TypeError、ParseError)或希望统一处理Exception与Error,很可能是由于仅使用catch (Exception $e)而未适配Throwable接口。以下是构建健壮异常处理链的具体操作步骤:
一、使用Throwable接口统一捕获Exception与Error
PHP 7引入Throwable接口作为Exception和Error的共同父接口,仅捕获Exception将遗漏Error子类(如TypeError、ParseError)。必须显式声明catch (Throwable $e)才能覆盖全部可捕获的抛出项。
1、在try块后添加catch (Throwable $e)语句,而非仅catch (Exception $e)。
2、确保该catch块位于所有具体类型catch块之后,避免被提前匹配。
立即学习“PHP免费学习笔记(深入)”;
3、在catch块内调用$e->getMessage()、$e->getFile()、$e->getLine()获取基础信息。
4、使用$e instanceof Exception或$e instanceof Error进行分支处理,区分业务异常与系统错误。
二、实现嵌套异常并保留原始异常链
当在catch块中需要抛出新异常但又不丢失原始上下文时,应将当前异常作为$previous参数传入新异常构造函数,从而形成可追溯的异常链。
1、在catch (Throwable $e)块中创建新异常实例,例如new RuntimeException('数据库写入失败', 500, $e)。
2、确保新异常类构造函数签名支持第三个$previous参数(所有内置异常均支持)。
3、在日志记录中调用$e->getPrevious()逐层展开,直至返回null为止。
4、使用var_dump($e->getTraceAsString())时注意生产环境禁用,仅用于开发调试。
三、配置全局异常处理器补充未捕获异常
set_exception_handler()用于拦截所有未被try-catch捕获的Throwable对象,是最后一道防御线,适用于记录日志、发送告警或返回统一错误响应。
1、定义回调函数,接收一个Throwable $e参数。
2、在函数内调用error_log()将$e->getMessage()、$e->getTraceAsString()写入指定日志文件。
3、检查$e instanceof Error,对Error类异常添加特殊标记(如前缀[ERROR])以便监控识别。
4、调用http_response_code(500)并输出脱敏提示(如服务暂时不可用),禁止暴露堆栈或路径。
四、结合set_error_handler与throw实现错误转异常
PHP原生E_WARNING、E_NOTICE等错误无法直接进入try-catch,需通过set_error_handler捕获后手动throw新异常,使其纳入Throwable处理链。
1、注册错误处理器:set_error_handler(function ($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, $errno, 0, $errfile, $errline); })。
2、确保该注册发生在任何可能触发警告的代码之前。
3、在后续try块中即可用catch (ErrorException $e)或catch (Throwable $e)捕获该错误转换后的异常。
4、注意:此方法无法捕获Fatal Error(如内存耗尽、语法解析失败),仅适用于运行时非致命错误。
五、使用register_shutdown_function补救未捕获Fatal Error
Fatal Error(如Allowed memory size exhausted、Class not found)无法被任何catch捕获,只能依赖脚本终止前的钩子函数获取最后错误状态。
1、调用register_shutdown_function(function () { $error = error_get_last(); if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) { error_log('[FATAL] ' . $error['message'] . ' in ' . $error['file'] . ':' . $error['line']); } });
2、该函数必须在脚本最顶部注册,确保其在所有逻辑执行前生效。
3、判断$error['type']是否属于致命类型,避免将E_WARNING等非致命错误误判为Fatal。
4、记录时剥离敏感路径信息,例如将/var/www/app/src/Service/User.php替换为Service/User.php。



















