PHP中try...catch仅能捕获Exception、Error及其子类(如TypeError)和手动转换的ErrorException;E_WARNING、E_NOTICE等传统错误默认不可捕获,需通过set_error_handler转为ErrorException才能捕获。

PHP 的 try...catch 不能捕获所有运行时错误,只有 Exception 及其子类(以及 PHP 7+ 的 Error 类)能被正常捕获;普通 E_WARNING、E_NOTICE 这类错误不会自动转成异常。
PHP 中哪些错误能被 try...catch 捕获
默认情况下,只有显式 throw 的 Exception 或 Error(如 TypeError、ParseError)会被捕获。传统错误(如调用未定义函数、访问空对象属性)仍会触发错误处理器,不进入 catch 块。
-
throw new Exception('msg')→ 可捕获 -
json_decode('{', true)→ 返回null,不抛异常,也不触发catch -
new DateTime('invalid')→ PHP 8+ 默认抛Exception,可捕获;PHP 7.4- 默认静默失败或触发警告 -
call_user_func('nonexistent_function')→ 触发E_WARNING,不可捕获,除非配合set_error_handler()转换
让传统错误也能进 catch:set_error_handler + ErrorException
通过自定义错误处理器,把 E_WARNING、E_NOTICE 等转为 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 {
$a = $undefined_var;
} catch (ErrorException $e) {
echo "捕获到错误:", $e->getMessage();
}
- 必须在
try前注册set_error_handler - 注意检查
error_reporting(),避免屏蔽本应忽略的低级提示 -
ErrorException是Exception子类,兼容现有catch (Exception $e)
PHP 7+ 的 Error 类型必须显式声明捕获
PHP 7 引入了 Error 层次结构(如 TypeError、ParseError),它们不是 Exception 的子类,所以 catch (Exception $e) 不会捕获它们——必须单独 catch (Error $e) 或使用 Throwable。
立即学习“PHP免费学习笔记(深入)”;
try {
echo [1,2,3]->length; // TypeError
} catch (TypeError $e) {
echo "类型错误:", $e->getMessage();
} catch (Throwable $e) {
echo "其他 Throwable:", $e->getMessage();
}-
Throwable是Exception和Error的共同父接口,PHP 7+ 推荐用它兜底 - 不要只写
catch (Exception $e)就以为万事大吉 -
ParseError在eval()或动态加载代码时才可能抛出,直接写错语法会在解析阶段失败,根本不会执行到try
finally 执行时机与资源清理陷阱
finally 块一定会执行,哪怕遇到 exit()、die() 或未被捕获的异常(PHP 7.1+)。但它不保证「安全退出」:如果 finally 里又抛异常,会覆盖原异常。
try {
throw new RuntimeException('original');
} catch (RuntimeException $e) {
echo "处理中...\n";
throw new LogicException('replaced');
} finally {
echo "finally 运行了\n"; // 会输出
// 如果这里 throw,会掩盖上面的 LogicException
}-
finally适合关文件、释放句柄、重置状态等确定性操作 - 避免在
finally中抛异常或调用可能失败的函数(如fclose()应先判断资源是否有效) - PHP 8.0+ 支持在
catch后加finally,但顺序固定:try → catch* → finally
真正难的不是写 try...catch,而是判断哪些地方该用、哪些错误值得转成异常、哪些该交给日志或监控系统——比如数据库连接失败要重试,而模板中少个变量就该静默渲染为空,而不是炸开整个页面。











