try-catch 无法捕获 Fatal Error(如未定义函数调用)、语法错误和脚本加载期的 ParseError,因其发生在执行前或直接终止进程;仅能捕获 Throwable 实例,PHP 7+ 需用 catch (Throwable $e) 并配合 set_error_handler 转换传统错误。

PHP 的 try-catch 不能捕获所有“看起来像错误”的情况,它只对真正抛出的 Exception 或 Error(PHP 7+)对象有效;语法错误、未定义函数调用、E_WARNING 这类传统错误默认完全绕过 try-catch。
为什么 try-catch 捕不到 Call to undefined function?
这类错误属于 Fatal Error,发生在 PHP 解析或执行阶段的严重中断,不是异常对象,不继承 Throwable。程序直接中止,catch 根本没机会运行。
-
try { foo(); }→ 报Fatal error: Uncaught Error: Call to undefined function foo(),不进catch - 同理:
parse error、memory exhausted等也一样 - 唯一能兜底的是
register_shutdown_function()+error_get_last(),但此时无法恢复执行
PHP 7+ 必须用 catch (Throwable $e) 而不是 Exception
PHP 7 引入了 Error 类族(如 TypeError、ParseError),它们和 Exception 是平行关系,都实现 Throwable 接口。只写 catch (Exception $e) 会漏掉所有 Error。
- 错误写法:
catch (Exception $e)→ 捕不到json_encode(NAN)抛出的TypeError - 正确写法:
catch (Throwable $e)→ 兜底所有可捕获的终止性对象 - 若需区分处理,顺序应为:
catch (TypeError $e)→catch (Exception $e)→catch (Throwable $e)
怎么让 E_WARNING、E_NOTICE 进 catch?
传统错误级别默认不转异常,必须用 set_error_handler() 手动转换成 ErrorException(它是 Exception 子类),才能被 catch 拦截。
立即学习“PHP免费学习笔记(深入)”;
- 必须在
try前注册处理器,且要检查error_reporting()是否启用该级别 - 示例代码:
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; // 触发 E_NOTICE } catch (ErrorException $e) { echo '捕获到:', $e->getMessage(); } -
ErrorException兼容现有catch (Exception $e),但注意它不捕获Fatal Error
throw new Exception() 的第二个参数不是字符串标识符
Exception 构造函数签名是 __construct(string $message = "", int $code = 0, ?Throwable $previous = null)。第二参数强制为整数,传字符串会静默转成 0,导致后续 $e->getCode() 判断失效。
- 错误写法:
throw new Exception('Invalid input', 'invalid_input')→ 实际getCode()返回0 - 正确写法:
throw new Exception('Invalid input', 400)或自定义异常类封装字符串 code - 业务中建议用自定义异常类,把语义化标识存在属性里,别依赖父类
$code字段
最常被忽略的一点:即使写了 catch (Throwable $e),也拦不住脚本加载时的 ParseError——它发生在 try 执行前,整个文件根本没机会被解析进执行流程。



















