统一php错误需用set_error_handler处理非致命错误,register_shutdown_function+error_get_last()补漏致命错误,结构化输出json并区分环境配置。

PHP 错误统一用 set_error_handler 拦截,但注意它不处理 E_ERROR 类致命错误
默认 PHP 错误直接输出或记日志,格式杂乱。想统一成 JSON 或结构化字符串,必须接管非致命错误(E_WARNING、E_NOTICE 等),靠 set_error_handler 是最直接的入口。
但得清醒:它对 E_ERROR、E_PARSE、E_CORE_ERROR 无效——这些会直接中断脚本,必须配合 register_shutdown_function + error_get_last() 补漏。
-
set_error_handler返回true表示已处理,不再走默认逻辑;返回false或不返回,错误仍会触发传统警告/通知 - 别在 handler 里抛异常,否则可能引发嵌套错误,尤其在 CLI 下容易静默失败
- 若启用了
display_errors=On,handler 处理后仍可能被原样输出,需同步ini_set('display_errors', '0')
用 register_shutdown_function 捕获致命错误,但要区分是错误还是正常结束
脚本终止时,register_shutdown_function 总会执行,但它不告诉你“为什么停”。必须手动调 error_get_last() 判断是否有未捕获的致命错误。
常见误判点:脚本自然执行完也会进 shutdown function,此时 error_get_last() 返回 null,不是错误。别一进来就无脑输出错误格式。
立即学习“PHP免费学习笔记(深入)”;
- 只在
error_get_last()返回非null且type属于致命类(如E_ERROR)时才格式化输出 - CLI 和 Web SAPI 行为不同:CLI 下可直接
echoJSON;Web 下需检查headers_sent(),避免报 “Cannot modify header information” - 不要在 shutdown 函数里再调
trigger_error或写日志文件,IO 可能已不可靠
错误格式统一用数组组装再 json_encode,别拼字符串
有人图快用 "[ERROR] {$msg} at {$file}:{$line}",结果中文乱码、引号没转义、字段缺失,下游解析全崩。结构化是底线。
核心字段建议固定:level(对应 error level 名字)、message、file、line、timestamp、trace(可选,debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS))。
-
json_encode务必加JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,否则中文变 \uXXXX,斜杠多一层 - 生产环境禁用
trace,调试时再开——堆栈信息可能含敏感路径或变量值 - 如果输出到浏览器,记得设
Content-Type: application/json; charset=utf-8,否则前端fetch().json()可能解析失败
开发和生产环境的错误行为必须分离,靠 error_reporting 和 display_errors 控制
本地开着 display_errors=On 看裸错误很爽,但上线还这样等于把堆栈、路径、配置细节白送黑客。
统一格式不是万能胶——它只管“怎么输出”,不管“输出什么”。真正决定哪些错误该出现、哪些该静默,还得靠 error_reporting 配置。
- 开发环境:设
error_reporting(E_ALL)+display_errors=On+ 统一 JSON 格式,方便前端或调试工具消费 - 生产环境:设
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED)+display_errors=Off+ 日志写入文件或 syslog,统一格式只用于日志内容,不输出给用户 - 别依赖
.htaccess或php.ini全局改——用ini_set()在入口文件顶部显式控制,避免环境差异导致行为不一致
E_NOTICE 不该让整个响应变成 500,但又不能完全忽略。这个边界得结合业务定,代码只是工具。











