php 主动抛错需用 trigger_error() 或 throw,单元测试优先 throw;mock 外部函数须依赖注入或 functionmocker;catch (throwable) 可捕获大部分 fatal error,但 parseerror 需预检;注意错误传播路径、返回值含义及环境差异。

怎么让 PHP 主动抛出指定错误或异常
测试代码健壮性时,不能等真实故障发生才验证逻辑,得主动制造错误。PHP 本身不提供“模拟系统级错误”的开关,但可以通过 trigger_error()、throw 和 set_error_handler() 组合控制错误类型和时机。
-
trigger_error('msg', E_WARNING)生成用户级错误,会被默认错误处理器捕获,但不会中断执行(除非是E_ERROR) - 用
throw new RuntimeException('msg')更适合单元测试场景,能被try/catch精准拦截 - 避免直接调用
error_log()或echo:它们只是输出,不触发错误处理机制,测不到错误分支 - 注意
E_NOTICE默认不显示,测试前确认error_reporting包含它,否则trigger_error(..., E_NOTICE)看不到效果
在 PHPUnit 中模拟函数失败(比如 file_get_contents)
真实调用外部资源(HTTP、文件、数据库)会拖慢测试且不可控,必须隔离。但 PHP 不支持像 Python 那样直接 patch 全局函数,得靠依赖注入或包装器。
- 别写
file_get_contents($url)硬编码 —— 改成通过接口传入一个$httpClient实例,测试时传入返回 false 的 mock 对象 - 如果无法改源码,用
class_alias()+ 自定义命名空间临时替换函数行为(仅限 CLI 测试环境,慎用于生产) - PHPUnit 10+ 支持
FunctionMocker::replace()(需额外装包),可写FunctionMocker::replace('file_get_contents', false),但要注意它只对当前进程有效,且不能 mock 内置语言结构(如include) - mock 后记得清理:
FunctionMocker::clear(),否则影响后续测试用例
如何让 try/catch 捕获到 fatal error(比如未定义函数)
fatal error(如 Fatal error: Uncaught Error: Call to undefined function xxx())默认无法被 try/catch 拦截,因为它们发生在 Zend 引擎层面,不是 Exception。
- PHP 7+ 引入了
Error类,继承自Throwable,所以catch (Throwable $e)能捕获大部分 fatal error(包括ParseError、TypeError) - 但
ParseError在文件加载阶段就报错,根本进不了try块 —— 这类只能靠预检(如php -l file.php)或 IDE 提示 - 用
register_shutdown_function()捕获脚本终止前状态,配合error_get_last()判断是否为 fatal,适合日志记录,不适合流程控制 - 别指望
set_error_handler()处理E_ERROR:它对 fatal error 无效,只会收到 warning/notice
测试错误处理逻辑时容易忽略的边界情况
很多测试只覆盖了“抛异常 → catch → 返回提示”这条线,漏掉错误传播路径中的隐式转换或静默吞没。
立即学习“PHP免费学习笔记(深入)”;
- 函数返回
false但文档没写清是否表示失败(如json_decode('', true)返回null,不是false)—— 必须查 PHP 手册确认每个返回值含义 - 开启
zend.assertions = -1时,assert()完全不执行,相关错误分支永远测不到 - CLI 和 Web SAPI 错误显示行为不同:CLI 默认显示所有 error,而 Apache 可能被
display_errors = Off屏蔽,导致你本地能看到错误,CI 里却静默失败 - 扩展缺失引发的错误(如没装
mbstring却调用mb_strlen())属于 fatal error,必须在测试环境提前检查扩展可用性
真正难的不是造一个错误,而是让错误以预期的方式冒泡、被捕获、被记录,同时不污染其他测试用例的状态。每种错误类型走的路径都不一样,得按 Throwable / Error / Exception / error_reporting 级别一层层对齐。











