kode 统一异常处理包,支持 FPM / 多进程 / 多线程 / 协程 / 分布式环境。
- 统一异常类 - 单一
KodeException类支持所有异常类型 - 统一错误码体系 -
E1xxxHTTP /E2xxx业务 /E3xxx运行时 /E5xxx系统 - 统一响应格式 - 直接返回
{code, msg, type, trace_id, location, chain, ...} - 链路追踪 - 完整调用链路记录,精确定位问题文件和行号
- 多格式报告 - 支持 JSON、HTML、纯文本链路报告导出
- 多环境支持 - FPM、Swoole、Workerman、Fiber 协程
- Monolog 集成 - 完整日志支持,自动分级记录
composer require kode/exceptionuse Kode\Exception\KodeException;
use Kode\Exception\ExceptionManager;
// 初始化
$manager = new ExceptionManager();
$manager->register();
// 抛出异常 - HTTP 错误
throw KodeException::bad('参数错误', ['field' => 'email']); // E1001 400
throw KodeException::auth('未授权'); // E1002 401
throw KodeException::deny('禁止访问'); // E1003 403
throw KodeException::notFound('资源不存在'); // E1004 404
throw KodeException::invalid('验证失败', ['errors' => []]); // E1006 422
// 抛出异常 - 业务错误
throw KodeException::param('参数不正确'); // E2001
throw KodeException::missing('User', '123'); // E2004
throw KodeException::conflict('数据冲突'); // E2009
// 抛出异常 - 运行时错误
throw KodeException::timeout('请求超时'); // E3004
throw KodeException::coroutinePanic('协程崩溃'); // E3001
throw KodeException::poolExhausted('连接池耗尽'); // E3003
// 抛出异常 - 系统错误
throw KodeException::memory('内存耗尽'); // E5001
throw KodeException::disk('磁盘空间不足'); // E5002使用 KodeException 统一入口进行一站式异常处理、日志记录和链路追踪:
use Kode\Exception\KodeException;
// 一键初始化异常处理系统
KodeException::init(
isProduction: false,
serviceName: 'my-service'
);
// 快速抛出异常
throw KodeException::bad('参数错误', ['field' => 'email']);
throw KodeException::auth('未授权');
throw KodeException::notFound('资源不存在');
// 快速日志记录
KodeException::info('服务启动');
KodeException::warning('请求频繁');
KodeException::errorLog('系统错误');
// 访问管理器、追踪器、日志器
$manager = KodeException::manager();
$tracer = KodeException::tracer();
$logger = KodeException::logger();
// 格式化和渲染异常
$response = KodeException::format($exception);
$json = KodeException::render($exception);响应直接以 code 层开始,无需外层包装:
{
"code": "E1001",
"msg": "参数错误",
"type": "http",
"trace_id": "67f3a1b2-c8d4-e925-f6a1-3b7c9e2d4f5a",
"location": {
"file": "/app/Service/UserService.php",
"line": 42,
"method": "App\\Service\\UserService::updateUser()"
},
"context": {"field": "email"},
"chain": [
{"file": "/app/Controller/UserController.php", "line": 20, "method": "handleRequest()"},
{"file": "/app/Service/UserService.php", "line": 42, "method": "updateUser()"}
]
}| 范围 | 类型 | 说明 |
|---|---|---|
| E1xxx | HTTP | HTTP 协议相关错误(400-503) |
| E2xxx | 业务 | 业务逻辑错误(参数、验证、不存在、冲突) |
| E3xxx | 运行时 | 多进程/协程/连接池等运行时错误 |
| E5xxx | 系统 | 系统级错误(内存、磁盘等) |
use Kode\Exception\KodeException;
use Kode\Exception\Tracer\DistributedTracer;
use Kode\Exception\Tracer\ChainExporter;
$tracer = new DistributedTracer('user-service');
// 开始追踪
$spanId = $tracer->startSpan('getUserById');
// ... 执行逻辑 ...
// 结束追踪
$tracer->endSpan($spanId);
// 记录异常
$tracer->recordException($exception);
// 追踪异常
$report = $tracer->trace($exception);// 导出为纯文本
$exporter = new ChainExporter(ChainExporter::FORMAT_TEXT);
echo $exporter->export($report);
// 导出为 HTML(可浏览器查看)
$exporter = new ChainExporter(ChainExporter::FORMAT_HTML);
echo $exporter->export($report);
// 导出为 JSON
$exporter = new ChainExporter(ChainExporter::FORMAT_JSON);
echo $exporter->export($report);╔══════════════════════════════════════════════════════════════╗
║ 🔍 链路追踪报告 ║
╚══════════════════════════════════════════════════════════════╝
【追踪ID】67f3a1b2-c8d4-e925-f6a1-3b7c9e2d4f5a
【服务】user-service
【运行时】fpm
【执行时间】12.34ms
【⚠️ 异常】
代码: E1001
类型: http
信息: 参数错误
位置: /app/Service/UserService.php : 42
【🔗 调用链路】
→ #1 App\Controller\UserController::handleRequest() (user.php:20)
→ #2 App\Service\UserService::updateUser() (user.php:42)
【🖥️ 环境】
PID: 12345
PHP: 8.2.0
SAPI: fpm
───────────────────────────────────────────────────────────────
kode/exception | 2024-01-15 10:30:45
响应自动包含以下 HTTP 头:
X-Trace-Id: 追踪 IDX-Span-Id: 当前 Span ID
$manager = new ExceptionManager(null, null, true);
$manager->register();$tracer = $manager->createTracer('swoole-service');
go(function() use ($tracer) {
$spanId = $tracer->startSpan('async-task');
// ... 异步逻辑 ...
$tracer->endSpan($spanId);
});// 调用前获取追踪头
$headers = $tracer->getTraceHeaders();
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-Trace-Id: ' . $headers['X-Trace-Id'],
'X-Span-Id: ' . $headers['X-Span-Id'],
]);
// 被调用方自动接收父追踪use Kode\Exception\ExceptionManager;
use Kode\Exception\Tracer\DistributedTracer;
use Kode\Exception\Tracer\ChainExporter;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('exception');
$logger->pushHandler(new StreamHandler('exception.log'));
$manager = new ExceptionManager($logger, null, false);
$manager->register();
// 创建链路追踪
$tracer = $manager->createTracer('my-service');每个异常都包含精确定位信息:
$e = KodeException::bad('参数错误');
// 获取位置信息
$location = $e->getLocation();
// ['file' => '/app/UserService.php', 'line' => 42, 'method' => 'update()']
// 获取调用链路
$chain = $e->getCallChain();
// [['file' => ..., 'line' => ..., 'method' => '...()'], ...]$e = KodeException::bad('参数错误');
// 判断异常类型
$e->isHttp(); // true
$e->isBusiness(); // false
$e->isRuntime(); // false
$e->isSystem(); // false
// 获取 HTTP 状态码
$e->getHttpStatusCode(); // 400
// 判断错误码
$e->isCode('E1001'); // true
$e->isCodeIn(['E1001','E1002']); // true// 将任意异常转换为 KodeException
$original = new RuntimeException('原始错误');
$kode = KodeException::from($original, 'E9999', '包装后的错误');
// 重新抛出为 KodeException
$kode = KodeException::rethrow($original, 'E3001', '运行时错误', KodeException::TYPE_RUNTIME);
// 获取简化描述
$e->getSummary(); // [E1001] 参数错误 (UserService.php:42)- PHP 版本: >=8.1
- 严格类型:
declare(strict_types=1); - 命名空间:
Kode\Exception - 测试框架: PHPUnit
psr/log: ^3.0monolog/monolog: ^3.0
MIT