php 7.1+ 支持用竖线 | 在单个 catch 中合并捕获并列异常类型,如 catch (aexception | bexception $e),要求类间无继承关系且处理逻辑完全一致;否则应通过接口统一或分写 catch 块。

PHP 7.1+ 支持在单个 catch 块中用竖线 | 合并捕获多种异常类型,这是减少重复代码最直接有效的方式——前提是这些异常类型互不继承、逻辑一致,且你控制得了抛出方或能合理设计异常类层次。
PHP 7.1+ 的 catch (AException | BException $e) 写法
这是语法级支持,不是模拟或绕过。只要 PHP 版本 ≥ 7.1,就能原生使用:
try {
doSomething();
} catch (ValidationException | InvalidArgumentException $e) {
logUserInputError($e);
redirectToForm();
} catch (DatabaseException | NetworkException $e) {
logInfrastructureError($e);
showMaintenancePage();
}
- 竖线分隔的多个异常类必须是**并列关系**(不能是父子类),否则会报
ParseError: syntax error - 每个
catch块只能声明一个变量名(如$e),不能写成catch (A|B $a, $b) - 匹配顺序仍从上到下:如果
ValidationException是RuntimeException的子类,而你又写了catch (RuntimeException $e)在它前面,那ValidationException永远进不去——编译器不会报错,但逻辑失效
PHP 7.0 及更早版本的替代方案
没有 | 语法,但仍有可行路径,关键在于**主动设计异常类结构**,而非依赖 get_class() 或 instanceof 判断:
- 为需要统一处理的异常定义一个**空接口**,例如
interface UserInputError,让ValidationException和InvalidArgumentException都实现它 - 然后
catch (UserInputError $e)就能精准命中,且不干扰其他异常(比如不会误捕LogicException,哪怕它也继承自RuntimeException) - 避免用
catch (RuntimeException $e)来“兜底”多个业务异常——这会把所有运行时异常(包括你不该捕获的OutOfBoundsException)一并吞掉 - 若已有第三方异常类无法修改,可封装一层:在
throw前做转换,例如throw new MyValidationException($original->getMessage(), $original->getCode())
哪些场景不该用多异常捕获?
合并捕获只适用于“处理动作完全一致”的异常。一旦出现以下情况,强行合并反而增加维护成本:
- 需要提取不同异常的特定属性:比如
PDOException要查$e->getCode()判 SQLSTATE,而HttpException要看$e->getStatusCode() - 重试策略不同:网络超时可重试 3 次,数据库唯一约束失败重试毫无意义
- 日志级别不同:用户输入错误记
warning,系统级连接失败必须记error并告警 - 涉及
Error类型:PHP 7+ 的TypeError、ParseError不是Exception子类,不能和Exception写在同一catch中,必须单独catch (Error $e)或用Throwable
真正容易被忽略的点是:多异常捕获解决的是“写法重复”,不是“逻辑重复”。如果两个异常本该触发不同响应,硬塞进同一个 catch 块里,后续加分支判断只会让代码更难读——这时候老老实实分开写 catch,反而更清晰。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











