可以同时实现隐错和记日志:需设 display_errors = off、error_reporting = e_all、log_errors = on,并显式配置 error_log 指向可写文件;避免误设 error_reporting = 0 或依赖 syslog;慎用自定义错误处理器。

PHP 隐错(不暴露错误给用户)和记日志(保留完整错误供排查)可以同时做到,关键不是关掉错误报告,而是把 display_errors 关掉、log_errors 打开,并确保 error_log 指向可写文件或系统日志。
display_errors = Off 但 error_reporting 保持开启
很多开发者误以为“关错”就是设 error_reporting = 0,结果连日志都收不到。正确做法是:
-
display_errors = Off(禁用浏览器输出,防止敏感信息泄露) -
error_reporting = E_ALL或至少E_ALL & ~E_NOTICE(保证所有运行时错误被触发) -
log_errors = On(必须开启,否则错误不会写入日志)
注意:display_errors 是 PHP INI 级别配置,无法在脚本里用 ini_set() 在某些 SAPI(如 CGI/FPM)中生效;推荐统一在 php.ini 或 www.conf 中设置。
error_log 指向可控路径,而非默认 syslog
默认 error_log = syslog 会把错误发到系统日志(如 /var/log/syslog),不易隔离和轮转。生产环境建议显式指定:
立即学习“PHP免费学习笔记(深入)”;
-
error_log = /var/log/php/error.log(需确保 PHP 进程有写权限) - 配合
log_errors_max_len = 1024防止超长错误截断(尤其含堆栈时) - 若用 Docker 或无 root 权限环境,避免写
/var/log,改用应用目录下logs/php-error.log并挂载卷
验证是否生效:故意触发一个 Notice(如访问未定义变量),然后 tail -f /var/log/php/error.log 查看是否记录。
自定义错误处理器慎用,优先走原生日志链路
有人用 set_error_handler() 拦截再写文件,看似灵活,实则容易漏掉:
- Fatal errors(如
ParseError、Fatal error: Allowed memory size exhausted)无法被set_error_handler捕获 - 覆盖后可能干扰框架(如 Laravel 的异常处理机制)或监控扩展(如 New Relic)
- 重复写日志导致混乱(原生日志 + 自定义 handler 双写)
除非需要做额外上下文注入(如请求 ID、用户 session ID),否则不要替换原生错误日志。真要增强,可用 register_shutdown_function() 补捕 fatal 错误,但仅作兜底,不替代 log_errors。
最常被忽略的一点:Web 服务器(Nginx/Apache)的错误日志和 PHP 的 error_log 是两套系统,500 错误可能只出现在 Web 服务器日志里,而 PHP 具体报错在 error_log 文件中——查问题时得两边一起看。











