本文目录导读:

我来详细介绍 PHP 错误收集的几种方法:
基础错误处理函数
使用 set_error_handler()
// 设置自定义错误处理函数
set_error_handler(function($errno, $errstr, $errfile, $errline) {
$error = [
'type' => $errno,
'message' => $errstr,
'file' => $errfile,
'line' => $errline,
'time' => date('Y-m-d H:i:s')
];
// 记录到文件
file_put_contents('error.log', json_encode($error) . PHP_EOL, FILE_APPEND);
// 返回 true 阻止 PHP 内置错误处理
return true;
});
使用 set_exception_handler()
// 处理未捕获的异常
set_exception_handler(function($exception) {
$error = [
'type' => 'Exception',
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
'time' => date('Y-m-d H:i:s')
];
// 记录到文件或发送到监控系统
file_put_contents('exception.log', json_encode($error) . PHP_EOL, FILE_APPEND);
});
完整的错误监控方案
类封装示例
class ErrorCollector {
private static $instance = null;
private $logDir;
private $isRegistered = false;
private function __construct($logDir = null) {
$this->logDir = $logDir ?: __DIR__ . '/logs';
if (!is_dir($this->logDir)) {
mkdir($this->logDir, 0777, true);
}
}
public static function getInstance($logDir = null) {
if (self::$instance === null) {
self::$instance = new self($logDir);
}
return self::$instance;
}
public function register() {
if ($this->isRegistered) return;
set_error_handler([$this, 'handleError']);
set_exception_handler([$this, 'handleException']);
register_shutdown_function([$this, 'handleShutdown']);
$this->isRegistered = true;
}
public function handleError($errno, $errstr, $errfile, $errline) {
$error = [
'type' => $this->getErrorType($errno),
'code' => $errno,
'message' => $errstr,
'file' => $errfile,
'line' => $errline,
'time' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'CLI',
'url' => $_SERVER['REQUEST_URI'] ?? 'CLI'
];
$this->logError($error);
// 不阻止 PHP 内置错误处理
return false;
}
public function handleException($exception) {
$error = [
'type' => 'Exception',
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
'time' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'CLI',
'url' => $_SERVER['REQUEST_URI'] ?? 'CLI'
];
$this->logError($error);
}
public function handleShutdown() {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
$this->handleError($error['type'], $error['message'], $error['file'], $error['line']);
}
}
private function logError($error) {
// 按日期分类存储
$filename = $this->logDir . '/error_' . date('Y-m-d') . '.log';
$logEntry = json_encode($error, JSON_UNESCAPED_UNICODE) . PHP_EOL;
file_put_contents($filename, $logEntry, FILE_APPEND);
// 错误级别较高时发送通知
if ($this->isCriticalError($error['code'])) {
$this->sendAlert($error);
}
}
private function getErrorType($errno) {
$types = [
E_ERROR => 'Fatal Error',
E_WARNING => 'Warning',
E_PARSE => 'Parse Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_COMPILE_ERROR => 'Compile Error',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Strict',
E_RECOVERABLE_ERROR => 'Recoverable Error',
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated'
];
return $types[$errno] ?? 'Unknown';
}
private function isCriticalError($code) {
return in_array($code, [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR]);
}
private function sendAlert($error) {
// 实现发送警报的逻辑(邮件、短信、Webhook等)
// mail('admin@example.com', 'Critical Error', print_r($error, true));
}
}
// 使用示例
$collector = ErrorCollector::getInstance(__DIR__ . '/logs');
$collector->register();
使用第三方库
Monolog (推荐)
composer require monolog/monolog
// 使用示例
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\NativeMailerHandler;
use Monolog\Processor\WebProcessor;
$log = new Logger('app');
$log->pushHandler(new StreamHandler(__DIR__ . '/logs/app.log', Logger::WARNING));
$log->pushHandler(new NativeMailerHandler('admin@example.com', 'Error Alert', 'from@example.com', Logger::CRITICAL));
$log->pushProcessor(new WebProcessor());
// 记录错误
try {
// 你的代码
} catch (\Exception $e) {
$log->error('Error occurred: ' . $e->getMessage(), [
'trace' => $e->getTraceAsString(),
'file' => $e->getFile(),
'line' => $e->getLine()
]);
}
Whoops (开发环境)
composer require filp/whoops // 使用示例 $whoops = new \Whoops\Run; $whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler); $whoops->register();
生产环境最佳实践
// 配置文件 config.php
return [
'error_handler' => [
'enabled' => true,
'log_dir' => __DIR__ . '/../logs',
'log_level' => E_ALL & ~E_DEPRECATED & ~E_STRICT,
'display_errors' => false,
'send_alerts' => true,
'alert_email' => 'admin@example.com',
'alert_level' => E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR,
]
];
// 初始化
$config = require 'config.php';
$collector = ErrorCollector::getInstance($config['error_handler']['log_dir']);
$collector->register();
// 设置 PHP 配置
ini_set('display_errors', $config['error_handler']['display_errors'] ? '1' : '0');
ini_set('log_errors', '1');
ini_set('error_log', $config['error_handler']['log_dir'] . '/php_errors.log');
error_reporting($config['error_handler']['log_level']);
错误收集工具集成
// Sentry 集成
// composer require sentry/sdk
\Sentry\init(['dsn' => 'your-sentry-dsn' ]);
// 自动捕获所有错误
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
$scope->setUser(['email' => 'user@example.com']);
});
set_error_handler(function($severity, $message, $file, $line) {
throw new \ErrorException($message, 0, $severity, $file, $line);
});
// 或者使用框架集成(Laravel)
if (app()->bound('sentry')) {
$this->app->make('sentry');
}
自定义错误格式
// 支持多格式输出
class ErrorFormatter {
public static function toJson($error) {
return json_encode($error, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
public static function toText($error) {
return sprintf(
"[%s] %s: %s in %s on line %d\nURL: %s\nIP: %s\n",
$error['time'],
$error['type'],
$error['message'],
$error['file'],
$error['line'],
$error['url'],
$error['ip']
);
}
public static function toHtml($error) {
return sprintf(
'<div class="error-entry">
<h3>%s</h3>
<p><strong>Time:</strong> %s</p>
<p><strong>Message:</strong> %s</p>
<p><strong>File:</strong> %s:%d</p>
</div>',
$error['type'],
$error['time'],
htmlspecialchars($error['message']),
htmlspecialchars($error['file']),
$error['line']
);
}
}
建议
- 开发环境:显示详细错误信息
- 生产环境:记录错误但不显示,使用日志和监控系统
- 使用成熟的库:Monolog, Sentry, Bugsnag等
- 定期检查日志:设置日志轮转和清理策略
- 错误分级:根据严重程度发送不同级别的通知