在PHP项目开发中,异常记录是排查线上问题、保障服务稳定性的核心手段,合理的异常记录能够让开发者快速定位错误根源,减少故障恢复时间。不同的业务场景需要适配不同的异常记录方案,同时完善的错误日志管理也能避免日志文件无序膨胀、重要信息被覆盖等问题。

PHP原生异常记录方法
手动记录异常
最基础的异常记录方式是在捕获异常的代码块中,手动调用error_log函数将异常信息写入日志。这种方式灵活性高,可以根据业务需求自定义记录的内容。
<?php
try {
// 模拟可能出错的代码
$result = 10 / 0;
} catch (Exception $e) {
// 拼接异常信息
$logContent = "异常时间:" . date('Y-m-d H:i:s') . PHP_EOL;
$logContent .= "异常消息:" . $e->getMessage() . PHP_EOL;
$logContent .= "异常文件:" . $e->getFile() . PHP_EOL;
$logContent .= "异常行号:" . $e->getLine() . PHP_EOL;
$logContent .= "异常堆栈:" . $e->getTraceAsString() . PHP_EOL;
// 将异常信息写入日志文件
error_log($logContent, 3, '/var/log/php/exception.log');
}
?>error_log函数的第二个参数表示记录类型,这里使用3表示将内容追加到指定的日志文件中,第三个参数就是日志文件的存储路径,需要确保该路径有写入权限。
自定义全局异常处理器
如果每个异常捕获块都手动写记录逻辑会有大量重复代码,我们可以通过set_exception_handler函数设置全局异常处理器,让所有未被捕获的异常都自动进入统一的处理逻辑。
<?php
// 定义全局异常处理函数
function globalExceptionHandler($exception) {
$logContent = "===== 全局异常捕获 =====" . PHP_EOL;
$logContent .= "捕获时间:" . date('Y-m-d H:i:s') . PHP_EOL;
$logContent .= "异常类型:" . get_class($exception) . PHP_EOL;
$logContent .= "异常消息:" . $exception->getMessage() . PHP_EOL;
$logContent .= "发生文件:" . $exception->getFile() . PHP_EOL;
$logContent .= "发生行号:" . $exception->getLine() . PHP_EOL;
$logContent .= "堆栈信息:" . PHP_EOL . $exception->getTraceAsString() . PHP_EOL;
$logContent .= "=======================" . PHP_EOL;
// 写入日志
error_log($logContent, 3, '/var/log/php/global_exception.log');
// 返回友好的错误提示给用户
echo "系统出现错误,请稍后重试";
}
// 注册全局异常处理器
set_exception_handler('globalExceptionHandler');
// 测试未捕获的异常
throw new Exception("测试全局异常处理器");
?>注册之后,所有没有被try...catch捕获的异常都会自动触发globalExceptionHandler函数,避免异常直接暴露给用户,同时统一完成日志记录。
PHP错误日志管理配置
php.ini相关配置
PHP的错误日志记录行为可以通过php.ini配置文件进行调整,常用的配置项如下:
| 配置项 | 说明 | 默认值 |
|---|---|---|
| error_reporting | 设置报告哪些级别的错误,比如E_ALL表示报告所有错误 | E_ALL & ~E_NOTICE & ~E_STRICT |
| log_errors | 是否开启错误日志记录,On为开启,Off为关闭 | Off |
| error_log | 错误日志的存储路径,如果留空会交给服务器的错误日志处理 | 空 |
| log_errors_max_len | 单条错误日志的最大长度,0表示不限制 | 1024 |
生产环境建议将error_reporting设置为E_ALL & ~E_NOTICE & ~E_DEPRECATED,避免记录不必要的通知和弃用提示,同时开启log_errors,并指定明确的error_log路径。
日志分级与轮转
如果所有异常和错误都写入同一个日志文件,会导致文件体积快速膨胀,不便于后期排查。我们可以按照错误级别拆分日志,比如将致命错误、普通异常、警告信息分别存储到不同的文件中。
另外可以结合系统的日志轮转工具,比如Linux下的logrotate,设置日志按天或按大小切割,自动删除过期的日志文件,避免磁盘空间被占满。简单的logrotate配置示例如下:
/var/log/php/*.log {
daily
rotate 7
missingok
notifempty
compress
create 0644 www-data www-data
}该配置表示PHP日志目录下的所有日志文件按天切割,保留最近7天的日志,过期自动删除,切割后的日志会进行压缩存储。
第三方日志库的使用
如果项目规模较大,原生记录方式的功能会比较有限,此时可以使用成熟的第三方日志库,比如Monolog,它支持多种日志处理器,能够将日志写入文件、数据库、远程服务等多种存储位置,还支持日志分级、格式化等功能。
首先通过Composer安装Monolog:
composer require monolog/monolog
然后可以这样使用它记录异常:
<?php
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// 创建日志实例,设置通道名
$log = new Logger('exception');
// 添加文件处理器,设置日志级别为DEBUG
$log->pushHandler(new StreamHandler('/var/log/php/monolog_exception.log', Logger::DEBUG));
try {
// 模拟业务逻辑错误
$user = null;
if (empty($user)) {
throw new Exception("用户不存在");
}
} catch (Exception $e) {
// 记录异常到日志
$log->error('业务异常捕获', [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTrace()
]);
}
?>Monolog会以结构化的方式存储日志,方便后续做日志分析,比如对接ELK等日志分析系统,提升问题排查的效率。
常见注意事项
- 不要在异常日志中记录敏感信息,比如用户密码、支付密钥、数据库密码等内容,避免信息泄露。
- 生产环境不要将异常详情直接返回给前端用户,只需要返回通用的错误提示即可,详细异常信息记录到日志中。
- 定期检查日志文件的存储路径权限,避免因为权限不足导致日志写入失败,遗漏重要的异常信息。
- 根据业务场景选择合适的日志级别,比如调试阶段的日志用DEBUG级别,线上业务异常用ERROR级别,方便后续过滤查看。
PHP异常记录error_logPHP错误日志set_exception_handlerMonolog修改时间:2026-06-07 01:23:02