PHP错误处理需结合set_error_handler捕获非致命错误、register_shutdown_function捕获致命错误、ErrorException转异常、Monolog结构化日志及环境分离策略,实现安全可控的日志记录与调试。

当PHP脚本执行过程中发生错误时,系统默认的错误提示可能暴露敏感信息或无法满足生产环境的调试与审计需求。以下是实现自定义错误处理器与日志记录的多种可行方案:
一、使用set_error_handler注册全局错误处理器
该方法可捕获E_WARNING、E_NOTICE、E_USER_ERROR等非致命错误,替代默认错误输出,便于统一格式化与定向记录。
1、定义一个接收错误级别、消息、文件名和行号的回调函数,参数顺序为:$errno, $errstr, $errfile, $errline, $errcontext。
2、在函数内部使用error_log()将错误信息写入指定日志文件,格式包含时间戳、错误级别、消息、文件路径及行号。
立即学习“PHP免费学习笔记(深入)”;
3、返回true以阻止PHP默认错误处理机制继续执行,避免重复输出。
4、调用set_error_handler()并将该函数名作为参数传入,确保在脚本早期(如入口文件开头)完成注册。
二、结合register_shutdown_function捕获致命错误
set_error_handler无法捕获E_ERROR、E_PARSE等致命错误,需借助register_shutdown_function在脚本终止前检查最后的错误状态。
1、定义一个关闭函数,调用error_get_last()获取最近一次发生的致命错误信息。
2、判断返回数组是否非空且errno属于致命错误类别(如E_ERROR、E_PARSE、E_CORE_ERROR)。
3、若存在致命错误,则构造结构化日志条目,包含错误类型、消息、发生位置及当前$_SERVER上下文片段。
4、使用file_put_contents()以FILE_APPEND标志追加写入日志文件,确保多进程写入不覆盖。
三、利用ErrorException类将错误转为异常
通过将传统错误抛出为Exception实例,可统一纳入try-catch流程与异常处理器,提升控制力与可扩展性。
1、在自定义错误处理器中,对不希望忽略的错误级别(如E_WARNING及以上)实例化一个新的ErrorException对象。
2、将原始错误信息、文件、行号作为构造参数传入,并保留原有错误码。
3、在实例化后立即throw该异常,使错误流进入异常处理分支。
4、配合set_exception_handler()设置全局异常处理器,实现错误与异常的集中日志归档与响应策略。
四、基于Monolog库构建结构化日志管道
当项目规模扩大或需对接外部日志系统(如ELK、Syslog)时,引入成熟日志库可避免重复造轮子并保障可靠性。
1、通过Composer安装monolog/monolog包,确保自动加载可用。
2、初始化Logger实例,并添加StreamHandler指向本地日志文件,同时设置JsonFormatter以输出机器可读格式。
3、在自定义错误处理器中,根据错误级别映射为Monolog对应的log level(如E_WARNING → Warning,E_USER_ERROR → Error)。
4、调用Logger对象的对应方法(如->warning()、->error()),传入消息及包含$errfile、$errline、$_SERVER['REQUEST_URI']的上下文数组。
五、分离开发与生产环境的日志行为
开发阶段需即时可见错误详情,而生产环境应禁止错误显示并严格限制日志内容,防止信息泄露。
1、依据php.ini中的display_errors配置或自定义常量(如APP_ENV === 'production')判定当前环境。
2、在开发环境,错误处理器中调用trigger_error()补充堆栈追踪,并启用xdebug_get_tracefile()(若已加载Xdebug)。
3、在生产环境,错误处理器中移除所有var_dump、print_r调用,且不对$errcontext数组做序列化输出。
4、生产环境下强制将日志权限设为0600,确保仅Web服务器用户可读,并定期通过logrotate管理文件大小与保留周期。



















