php try-catch 捕获不到 fatal error,因其属于解析或执行阶段的严重中断;php 7+ 应统一用 catch (throwable $e) 覆盖 exception 和 error;throw new exception() 第二参数为 int 型错误码;finally 中 return 会覆盖 try/catch 的返回值。

PHP try-catch 捕获不到 Fatal Error?
因为 try-catch 只捕获 Exception 和其子类,不捕获 Fatal Error(如 Call to undefined function、Parse error)。这类错误属于 PHP 解析或执行阶段的严重中断,无法被常规异常处理机制拦截。
常见错误现象:try-catch 包住一段明显有语法错误或调用不存在函数的代码,但程序直接报错退出,没进 catch 块。
- 用
set_error_handler()+error_reporting()可捕获部分E_ERROR级别以下错误,但对Fatal Error无效 - PHP 7+ 引入了
Error类(继承自Throwable),可统一捕获Exception和大多数Error,但仍有例外(如ParseError在脚本加载时仍会中止) - 真正兜底要用
register_shutdown_function()检查error_get_last(),但此时已无法“恢复执行”
catch 应该写 Exception 还是 Throwable?
PHP 7+ 推荐直接 catch (Throwable $e),否则会漏掉 Error 类型(比如 TypeError、ParseError 在某些上下文中抛出的是 Error 而非 Exception)。
使用场景:你希望同一段异常处理逻辑覆盖业务异常和运行时错误(如传参类型不符、内存耗尽)。
立即学习“PHP免费学习笔记(深入)”;
-
catch (Exception $e):只捕获传统异常,PHP 5 兼容写法,但 PHP 7+ 下明显不完整 -
catch (Throwable $e):PHP 7+ 必选,覆盖所有可捕获的终止性对象 - 若需区分处理,可先
catch (TypeError $e),再catch (Exception $e),最后catch (Throwable $e)保底
示例:
try {
json_encode(NAN);
} catch (TypeError $e) {
// PHP 7.3+ 中 json_encode(NAN) 抛 TypeError
} catch (Throwable $e) {
// 兜底
}
throw new Exception() 的参数顺序容易搞反
Exception 构造函数签名是 __construct(string $message = "", int $code = 0, ?Throwable $previous = null)。第二参数是错误码(int),不是错误级别或字符串标识。
常见错误现象:传入 'invalid_input' 当作第二个参数,结果得到 0(字符串转整数失败),导致后续用 $e->getCode() 判断分支失效。
- 错误写法:
throw new Exception('Missing ID', 'missing_id')→ 实际 code 是0 - 正确写法:
throw new Exception('Missing ID', 400)或throw new Exception('Missing ID', 400, $prev) - 如果需要语义化错误标识,建议用自定义异常类,把字符串 code 存在属性里,而不是依赖父类
$code
finally 执行时机与 return 冲突
finally 总会执行,哪怕 try 或 catch 中有 return。但要注意:如果 finally 里也有 return,它会覆盖前面的返回值。
性能影响小,但逻辑易被忽略——尤其在封装工具函数时,可能无意中“劫持”了业务层想返回的结果。
-
try { return 'a'; } finally { return 'b'; }→ 实际返回'b' -
try { return $val; } finally { log('done'); }→ 安全,$val正常返回 - 避免在
finally中写return,除非你明确要覆盖结果(比如重试逻辑中强制返回默认值)
最常被忽略的是 Throwable 和 Exception 的兼容边界,以及 finally 对返回值的静默覆盖——这两处不报错,但会让调试变得很绕。











