php 8 中应使用 catch (throwable $e) 捕获所有异常和错误,配合 error_log() 或 monolog 记录含时间、消息、文件、行号及堆栈的日志,注意权限、敏感信息过滤与全局异常处理器统一日志格式。

PHP 8 中捕获异常并记录日志,核心是用 try...catch 捕获异常,再通过内置函数(如 error_log())或 PSR-3 兼容的日志库(如 Monolog)写入日志文件。关键在于区分异常类型、保留堆栈信息、避免敏感数据泄露,并确保日志路径可写。
基础 try-catch + error_log 记录
适合简单项目或调试阶段。PHP 8 的 Throwable 是所有异常和错误的顶层接口,应优先捕获它:
- 用
catch (Throwable $e)捕获所有异常和致命错误(如Error子类) - 调用
error_log()时指定日志文件路径,避免写入系统默认位置(可能无权限) - 拼接消息时包含
$e->getMessage()、$e->getLine()、$e->getFile()和$e->getTraceAsString()
示例:
phptry {
throw new RuntimeException('数据库连接失败');
} catch (Throwable $e) {
$log = sprintf(
"[%s] %s in %s:%d\n%s\n",
date('Y-m-d H:i:s'),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
);
error_log($log, 3, '/var/log/myapp/error.log');
}
?>
使用 Monolog 实现结构化日志
生产环境推荐 Monolog —— 它支持日志级别、处理器(如 RotatingFileHandler)、格式器和上下文数据:
- 安装:
composer require monolog/monolog - 创建 Logger 实例,添加
RotatingFileHandler自动按天/大小轮转日志 - 在 catch 块中调用
error()或critical(),传入异常对象作为上下文,Monolog 会自动提取堆栈 - 避免在日志中直接拼接用户输入(如 POST 数据),防止日志注入或敏感信息泄露
示例:
use Monolog\Logger;use Monolog\Handler\RotatingFileHandler;
use Monolog\Formatter\LineFormatter;
$logger = new Logger('app');
$handler = new RotatingFileHandler('/var/log/myapp/app.log', 0, Logger::ERROR);
$handler->setFormatter(new LineFormatter(null, null, true, true));
$logger->pushHandler($handler);
try {
// 可能出错的代码
} catch (Throwable $e) {
$logger->error('请求处理失败', ['exception' => $e]);
}
?>
全局异常处理器:set_exception_handler
捕获未被 try-catch 拦截的异常(如顶层逻辑、异步回调中的异常):
- 定义一个全局函数,接收
Throwable参数 - 内部仍建议复用已配置好的 Logger,保持日志格式统一
- 注意:该处理器不处理 PHP 错误(如 ParseError),需额外用
set_error_handler()配合error_get_last()处理 - 不要在处理器中抛出新异常,否则会导致脚本终止且无日志
示例:
set_exception_handler(function (Throwable $e) use ($logger) {$logger->critical('未捕获异常', [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
]);
});
?>
注意事项与最佳实践
避免踩坑的关键细节:
- 日志目录必须存在且 Web 服务器用户(如 www-data)有写权限,否则日志静默失败
- 敏感字段(密码、token、身份证号)禁止出现在日志消息或上下文中;可用
array_filter()清洗后再记录 - PHP 8.0+ 的
MatchError和UnhandledMatchError属于Error类,会被Throwable捕获,无需单独处理 - CLI 脚本和 Web 请求共用同一套日志逻辑时,注意时区(
date_default_timezone_set())和进程用户权限差异
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











