PHP8.2要求多个catch按继承关系从具体到抽象排列,否则子类异常无法被捕获;支持用|合并并列异常类型处理,但禁止父子类混用;自定义异常需确保加载,finally仅用于清理而非错误处理。

PHP8.2中多个catch必须按继承顺序排列
PHP8.2严格遵循异常类的继承关系,catch块必须从**具体到抽象**排列,否则更宽泛的父类会提前截断子类异常。比如 PDOException 是 RuntimeException 的子类,若把 RuntimeException 写在前面,PDOException 永远不会被匹配到。
- 错误写法:
catch (Exception $e)放最前 → 所有异常都被它吃掉 - 正确顺序:先
catch (PDOException $e),再catch (InvalidArgumentException $e),最后catch (Exception $e) - PHP8.2 不再容忍“模糊匹配”,顺序错会导致逻辑失效,但不会报语法错误,容易漏测
用管道符 | 合并同类异常处理(PHP7.1+)
当多个异常需要执行完全相同的恢复逻辑(比如统一记录日志+返回 500),可用单个 catch 块合并声明,避免重复代码。
try {
$pdo->beginTransaction();
$stmt = $pdo->prepare($sql)->execute($params);
} catch (PDOException | RuntimeException $e) {
error_log('DB operation failed: ' . $e->getMessage());
return ['status' => 'error', 'message' => '服务暂时不可用'];
} catch (InvalidArgumentException $e) {
return ['status' => 'error', 'message' => '参数不合法'];
}- 注意:管道符只支持**并列的类名**,不能写
Exception | PDOException(因后者是前者的子类,语义冲突) - 类型检查仍可用
$e instanceof PDOException在块内做细分分支 - PHP8.2 对该语法无额外限制,但 IDE 可能未及时更新类型推导
自定义异常类 + 多个catch的实际协作方式
业务系统中建议用自定义异常区分领域错误,比如 InsufficientBalanceException 和 InvalidCurrencyException,它们都继承 Exception,但语义独立。
- 必须确保自定义类已
require或通过 autoloader 加载,否则抛出时直接 fatal error - 多个
catch块之间不能有继承关系,否则后一个永远不会执行 - 常见坑:在
catch块里忘记throw $e或throw new XXXException(),导致上游无法感知原始错误上下文 - 调试时可临时加
var_dump(get_class($e))确认实际抛出的是哪个类
finally 不是 catch 的替代品,别指望它捕获异常
finally 块只保证执行,不参与异常匹配。即使你写了 catch (Exception $e) 但没处理,异常仍会继续向上冒泡,finally 只是顺带运行。
立即学习“PHP免费学习笔记(深入)”;
- 典型误用:把数据库 rollback 写在
finally,却没在catch里rollback→ 事务可能已提交,finallyrollback 就失效了 - 正确做法:
catch中显式处理错误状态,finally只做资源清理(如$pdo = null) - PHP8.2 下,
finally中抛出新异常会覆盖原异常,除非你手动保存原异常对象
实际项目中最容易被忽略的,是 异常类加载时机 和 catch 顺序的隐式依赖——它们不出现在语法报错里,但会让 catch 形同虚设。上线前务必用真实异常路径触发一次全流程。



















