3、错误报告配置:php.ini中的error_reporting、display_errors、log_errors配置项

聊到PHP错误处理,绕不开的就是php.ini里的那三个老伙计。说实话,我见过太多项目上线后还开着错误显示,结果用户直接看到了数据库密码——那场面,真叫一个尴尬。

今天咱们就把这三个配置项掰开揉碎了讲清楚。你想想看,搞懂了它们,就等于掌握了PHP错误报告的开关和阀门。

3.1 error_reporting:你究竟想看哪些错误?

这个配置项说白了就是过滤器。它决定了哪些级别的错误会被PHP报告出来。我个人习惯把它理解成一个「权限清单」——只有清单上的错误类型,才有资格被处理。

核心概念:error_reporting 设置的是「错误级别」,而不是「是否显示」。它只负责筛选,不负责输出。

常见的错误级别常量如下:

常量 说明
E_ALL 32767 所有错误和警告(除E_STRICT在PHP 5.4.0前)
E_ERROR 1 致命运行时错误,脚本终止
E_WARNING 2 运行时警告,脚本继续执行
E_PARSE 4 编译时语法解析错误
E_NOTICE 8 运行时通知,可能是代码小问题
E_STRICT 2048 PHP建议的代码修改,确保互操作性
E_DEPRECATED 8192 运行时已弃用功能的警告

我在项目中遇到过一种情况:开发环境用E_ALL,结果被一堆NOTICE刷屏。其实很多NOTICE只是变量未定义,不影响运行。但说实话,上线前最好还是把这些小问题修掉,不然哪天突然变成E_WARNING就麻烦了。

我的建议:

  • 开发环境:error_reporting = E_ALL —— 别放过任何细节
  • 测试环境:error_reporting = E_ALL & ~E_DEPRECATED —— 忽略弃用警告,专注逻辑问题
  • 生产环境:error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT —— 或者干脆 E_ALL & ~E_NOTICE & ~E_DEPRECATED

你可能会问:为什么生产环境不直接用E_ALL?嗯,这里要注意——生产环境暴露任何错误信息都是安全隐患。而且有些第三方库会触发DEPRECATED警告,你总不能让用户看到「这个函数以后不能用了」这种提示吧?

3.2 display_errors:错误要不要给用户看?

这个配置项就简单了——它决定错误信息是否直接输出到浏览器。说白了就是「要不要让用户看到你的代码出了什么幺蛾子」。

取值只有两个:

  • On:显示错误(开发环境用)
  • Off:不显示错误(生产环境必须关)

我曾经踩过的坑:

有一次帮客户排查线上问题,发现display_errors是On。结果用户访问时,直接看到了数据库连接失败的堆栈信息——里面赫然写着数据库IP、用户名和密码。嗯,从那以后我每次上线前都会检查这个配置。

还有一个细节:display_errors 受 error_reporting 影响。就算你开了 display_errors = On,如果 error_reporting 设置为 0,那也不会显示任何错误。这两个配置是「与」的关系——两个条件都得满足,错误才会显示出来。

我个人习惯在开发环境这么配:

; php.ini 开发环境配置
error_reporting = E_ALL
display_errors = On
display_startup_errors = On  ; 这个也建议打开,能看到PHP启动阶段的错误

生产环境则必须这样:

; php.ini 生产环境配置
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED
display_errors = Off
display_startup_errors = Off

3.3 log_errors:把错误记下来,别让它跑了

display_errors关了,错误去哪了?答案就是日志。log_errors 配置项决定是否将错误写入日志文件。

这个配置我建议永远设为On。你想想看,生产环境关了错误显示,如果连日志都不记,那出了问题你连查都没地方查。

配套的还有两个配置:

  • error_log:指定日志文件路径。如果不设置,默认会写到Web服务器的错误日志里(比如Apache的error_log)。
  • log_errors_max_len:每条错误日志的最大长度,默认1024字节。我一般设成0(不限长度),因为截断的日志有时候反而让人摸不着头脑。

最佳实践组合:

; 生产环境标准配置
log_errors = On
error_log = /var/log/php_errors.log
log_errors_max_len = 0
; 别忘了设置日志文件的权限,确保Web进程有写入权限

我在项目中遇到过一个问题:日志文件越来越大,最后把磁盘撑爆了。所以建议配合日志轮转(log rotation)使用。Linux下可以用logrotate,每天切割一次,保留30天,基本够用。

3.4 三个配置的协同工作

这三个配置不是孤立的,它们是一条流水线:

  1. error_reporting 先筛选:哪些错误值得关注
  2. display_errors 决定是否展示给用户
  3. log_errors 决定是否写入日志

说白了,就是「筛出来→要不要给人看→要不要记下来」三步走。你可以在运行时用 ini_set() 临时修改这些配置,但注意:display_errors 如果脚本有致命错误(比如解析错误),在错误发生前可能来不及执行 ini_set()。所以php.ini里的配置才是最终保障。

一个小技巧:

如果你在开发环境想临时屏蔽某个页面的错误输出,可以用:

<?php
ini_set('display_errors', 0);
// 你的代码...
?>

但记得调试完改回来,不然容易漏掉问题。

3.5 实战建议:不同环境的配置模板

最后,我整理了一份我常用的配置模板,供你参考:

配置项 开发环境 测试环境 生产环境
error_reporting E_ALL E_ALL & ~E_DEPRECATED E_ALL & ~E_NOTICE & ~E_DEPRECATED
display_errors On Off Off
display_startup_errors On Off Off
log_errors On On On
error_log /tmp/php_errors.log /var/log/php_errors.log /var/log/php_errors.log

记住一句话:开发环境要「看得见」,生产环境要「藏得住、记得牢」。这三个配置项虽然基础,但用好了能帮你省下大量排查问题的时间。嗯,今天就先聊到这,下一节咱们看看怎么在代码里自定义错误处理函数。