set_error_handler可捕获e_warning、e_notice、e_user_*等非致命错误并转为异常以便测试断言,但需配合restore_error_handler避免污染;e_error等致命错误无法捕获,须用trigger_error模拟;测试中需显式设置error_reporting(e_all),注意@抑制符会使handler失效。

用 set_error_handler 拦截并验证错误是否触发
PHP 默认错误(E_WARNING、E_NOTICE 等)不会抛出异常,直接输出或静默丢弃,导致测试难断言。必须先用 set_error_handler 捕获,再配合 restore_error_handler 恢复,避免污染后续测试。
- 只对
E_WARNING、E_NOTICE、E_USER_*有效;E_ERROR、E_PARSE等致命错误无法被捕获,只能靠trigger_error模拟 - 函数回调里建议用
throw new ErrorException($message, 0, $severity, $file, $line)转成异常,方便expectException断言 - 务必在测试结束前调用
restore_error_handler(),否则可能影响其他测试用例
set_error_handler(function ($severity, $message) {
throw new ErrorException($message, 0, $severity);
});
// 执行可能触发 warning 的代码,如:file_get_contents('/nonexistent');
restore_error_handler();
测试 trigger_error 和自定义错误级别
业务中常用 trigger_error('xxx', E_USER_WARNING) 主动报错,这类错误能被 set_error_handler 捕获,但默认不显示——测试时容易误以为“没触发”。关键点在于错误级别是否被当前 error_reporting 掩码包含。
-
trigger_error第二个参数必须显式传入,比如E_USER_WARNING,不能依赖默认值 - 测试前建议临时设为
error_reporting(E_ALL),确保所有用户错误都生效 - 若测试环境禁用了
display_errors,不要靠ob_get_contents()检查输出,应专注捕获行为本身
PHPUnit 中断言错误处理逻辑的写法
PHPUnit 5.7+ 支持 expectException + expectExceptionMessage,但前提是错误已被转为异常。直接对 trigger_error 或警告调用 expectException 是无效的。
- 必须搭配
set_error_handler将错误转为ErrorException,再用$this->expectException(ErrorException::class) - 避免在
setUp里全局设 handler,不同测试用例的错误类型/级别可能冲突,应在每个测试方法内单独设置和恢复 - 如果被测函数内部已用了
@抑制符,set_error_handler会失效——这是常见盲区,得先检查源码有没有@file_get_contents这类写法
生产环境和测试环境的 error_reporting 差异
本地开发常开 E_ALL,但线上可能只开 E_ERROR | E_WARNING,导致某些 E_USER_NOTICE 在测试里能捕获,线上却静默丢失。
立即学习“PHP免费学习笔记(深入)”;
- 测试时别只信默认配置,用
ini_set('error_reporting', E_ALL)显式覆盖,更可靠 - CI 环境若用 Docker,注意 PHP 镜像的
php.ini是否改过error_reporting值,建议在测试 bootstrap 中统一初始化 -
error_reporting不影响set_error_handler的注册,但影响哪些错误会被真正传递给它——这点最容易被忽略











