PHP异常处理需区分错误类型:try/catch无法捕获Parse Error、Fatal Error(PHP 7+部分Error可捕获但需显式声明),也不能捕获Warning/Notice,除非用set_error_handler转为异常;1/0触发E_WARNING而非异常,须手动判断并throw;推荐catch(Throwable $e)统一兜底,但需区分Error与Exception处理;PDO等扩展须显式启用异常模式,finally需配合显式资源释放,异常处理核心在于分层抛、捕、转、死。

PHP 的异常处理不是“学了就能用”,而是得先分清哪些情况它能管、哪些它根本碰不到——try/catch 捕获不了 Parse Error、Fatal Error(PHP 7+ 中部分 Error 类可捕获,但需显式声明),也捕获不了 Warning 或 Notice,除非你主动把它们转成异常。
为什么 try-catch 对 1/0 无反应
直接写 1/0 触发的是 PHP 运行时警告(E_WARNING),不是异常。它不会进 catch,也不会中断脚本(除非配置了严格错误报告),但会输出警告信息并继续执行。
- 这是 PHP 错误机制和异常机制长期并存导致的典型混淆点
- 想让除零走异常流程,必须手动判断:
if ($b === 0) { throw new InvalidArgumentException("除数不能为零"); } -
set_error_handler()可以拦截非致命错误,并用ErrorException包装后throw出去,但对Fatal Error无效
catch 该写 Exception 还是 Throwable
PHP 7+ 中所有异常和错误都实现了 Throwable 接口,所以 catch (Throwable $e) 能捕获 Exception 和 Error 子类(如 TypeError、ParseError)。
- 仅捕获业务逻辑异常?用
catch (Exception $e)更安全,避免意外吞掉致命错误 - 需要统一兜底未处理的
Error?用catch (Throwable $e),但务必检查$e instanceof Error后再决定是否记录并exit - 不要写空
catch,哪怕只做error_log($e),否则异常静默消失,调试成本飙升
PDO 等扩展默认不抛异常,怎么统一处理
像 PDO、mysqli 这类扩展,默认错误模式是静默或报警告,必须显式开启异常模式,否则 try/catch 完全无效。
立即学习“PHP免费学习笔记(深入)”;
-
PDO需在构造后立即设置:$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); -
mysqli需启用mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); - 没开这个开关,
$pdo->query("SELECT * FROM nonexistent")不会抛PDOException,只会返回false,然后你得靠$pdo->errorInfo()手动查
finally 不是万能收尾,资源清理仍有坑
finally 块保证执行,但它不能替代显式资源释放逻辑,尤其在对象生命周期和引用计数层面。
- 数据库连接、文件句柄等资源,应在
finally中close()或unset(),但要注意:如果try中已return,finally仍会执行,但返回值已确定 -
__destruct()不可靠,可能因脚本提前终止而不触发;register_shutdown_function()适合兜底,但无法访问当前作用域变量 - 真正安全的做法是:用封装类(如
PDO实例本身)+ 显式close()+finally双保险,而不是依赖析构
最常被忽略的一点:异常处理不是加一层 try/catch 就完事,关键在「谁该抛、谁该捕、谁该转、谁该死」——业务层抛具体异常,服务层捕具体类型,框架层兜底 Throwable 并区分 Error 与 Exception 处理,而日志和监控必须覆盖所有分支,否则等于没设防。



















