northrook/error-handler 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

northrook/error-handler

Composer 安装命令:

composer require northrook/error-handler

包简介

Capture and handle errors, build structured reports, and render consistent output

README 文档

README

Capture, buffer, aggregate, and render errors. Every event is recorded; emit channels (PSR log, render, terminate) apply filters and priority separately.

Requires PHP 8.4+.

Install

composer require northrook/error-handler

Quick start

use Northrook\ErrorHandler;
use Northrook\ErrorHandler\ErrorHandlerConfig;
use Northrook\ErrorHandler\ErrorLevelMask;
use Psr\Log\LoggerInterface;

$handler = ErrorHandler::register(
    logger: $psrLogger,                    // optional; defaults to NullLogger
    throwAt: ErrorLevelMask::Standard,     // optional; see Throw mask
    config: new ErrorHandlerConfig(debug: true),
);

// Uncaught exceptions and fatals are handled automatically once installed.

register() builds the singleton and, by default, installs global error / exception / shutdown handlers. Pass install: false to construct without wiring globals, then call $handler->install() when ready.

Design

PrincipleMeaning
Buffer ≠ logThe buffer is the full forensic record (including @-silenced). Logging is filtered.
Report ≠ handlereport() builds diagnostics without dying; handle() renders and exits.
Global ≠ scopedGlobal handlers enforce throwAt; box() probes without throwing.
Priority ≠ PHP severityEventPriority is consequence-based (Noise / Action / Critical), not E_*.

Pipeline (current):

PHP error / throwable / box probe
        ↓
  ErrorBuffer (always)
        ↓
  Fingerprint → Aggregator (count + highest priority)
        ↓
  Route: Critical → log now; else queue until shutdown flush
        ↓
  handle() also renders + exit(1)

Registration & lifecycle

ErrorHandler::register()

ErrorHandler::register(
    null|LoggerInterface $logger = null,
    null|ErrorRendererInterface $renderer = null,
    null|int|ErrorLevelMask $throwAt = null,
    bool $install = true,
    null|ErrorHandlerConfig $config = null,
): ErrorHandler
ArgumentDefaultRole
$loggerNullLoggerPSR-3 sink for aggregate emit
$rendererErrorRenderer (CLI/HTML/JSON)Fatal / handle() output
$throwAtErrorLevelMask::StandardWhich PHP E_* types become exceptions
$installtrueWire global handlers immediately
$confignew ErrorHandlerConfig()Debug flag, render strategy, palette

Install / uninstall / reset

$handler->install();    // set_error_handler, set_exception_handler, register_shutdown_function
$handler->uninstall();  // restore previous handlers
$handler->reset();      // uninstall (if installed), clear buffer + aggregator, drop singleton

Shutdown always flushes pending aggregates to the logger first, then handles fatal last-errors.

Configuration

use Northrook\Contracts\RenderStrategy;
use Northrook\ErrorHandler\ErrorHandlerConfig;

new ErrorHandlerConfig(
    debug: true,                          // default: AppEnv::isDebug()
    renderStrategy: RenderStrategy::AUTO, // honored by ReportFactory / dumps
    colorPalette: null,                   // optional ColorPalette override
);
  • debug — when true, context['dumps'] are turned into VarDump bags for CLI/HTML. When false, dumps are ignored.
  • renderStrategy — passed into dump rendering (AUTO picks CLI vs HTML by SAPI).

Throw mask (ErrorLevelMask)

Controls which PHP error types the global handler promotes to ErrorException. Independent of priority / logging.

use Northrook\ErrorHandler\ErrorLevelMask;

ErrorHandler::register(throwAt: ErrorLevelMask::Standard);
ErrorHandler::register(throwAt: E_USER_WARNING | E_USER_ERROR); // raw int also fine
CaseMask
None0 — never throw from PHP errors
FatalFatals + recoverable
StandardE_ALL minus deprecations (default)
WarningsAndAboveExcludes notices and deprecations
StrictE_ALL including deprecations

Silenced errors (error_reporting masks the type, or @) are always buffered and aggregated as Noise; they never throw.

Scoped probes — box()

Failsafe: catch PHP errors inside a callback, keep going. Never throws from the scoped handler.

$result = $handler->box(
    fn () => $cache->warm($key),
    // optional: EventPriority::Action,
);

if ($handler->lastBoxError() !== null) {
    // inspect RuntimeError; process continues
}
BehaviourDetail
Default priorityNoise
Optional 2nd argEventPriority — elevates the aggregate for that scope
BufferErrors recorded on the shared ErrorBuffer
AggregateEach distinct fingerprint is hit; repeats bump count
ReturnCallback return value (or null if the callback returns nothing useful)

lastBoxError() is the last RuntimeError from the most recent box(); lastError() is the last entry in the global buffer.

Reports — report() vs handle()

report(Throwable $e, array $context = []): ErrorReport

Builds a structured ErrorReport (reference, snapshot, stack, previous chain, context, dumps, PHP errors). Does not exit.

Default priority: Action. Override with reserved context key:

$report = $handler->report($e, [
    'priority' => EventPriority::Critical, // or 'Critical' / 'critical'
    'orderId'  => $orderId,
    'dumps'    => [
        'cart' => $cart,
        'user' => $user,
    ],
]);

echo $handler->renderer->json->render($report); // or cli / html

Reserved keys (stripped from stored context):

KeyEffect
priorityEventPriority (or case name string) — emit routing
dumpsLabeled values → debug dump bags when config.debug is on

handle(Throwable $e): never

Forces Critical, aggregates, logs immediately, sets HTTP 500 (when not CLI and headers not sent), renders via the composite renderer, then exit(1).

Uncaught exceptions go through handle() (except under PHPUnit, where they are rethrown).

Priority & aggregation

EventPriority

BandMeaningEmit
NoiseForensic / hygieneBatched at shutdown
ActionShould be noticedBatched; appears in actionables()
CriticalCannot usefully continueImmediate log

Defaults by path:

PathPriority
Untagged box()Noise
Untagged report()Action
handle() / fatal shutdownCritical
Global non-throwing / silencedNoise

Repeats of the same fingerprint elevate to the highest priority seen and bump count.

Fingerprint

Stable xxh32 of class|phpType + file + line + message — used for aggregation. Separate from the per-instance report reference (error-{xxh32}).

Standing list & flush

$handler->actionables();              // Action+ entries this request
$handler->aggregator()->all();        // every fingerprint
$handler->flushPendingAggregates();   // emit queued Noise/Action now (also called on shutdown)

Each emit is one PSR log line per fingerprint:

Log levelPriority
noticeNoise
errorAction
criticalCritical

Context includes fingerprint, priority, count, class, reference (when a report exists), firstSeen, lastSeen.

Buffer inspection

$buffer = $handler->errors();           // ErrorBufferInterface (shared)
$buffer->all();
$buffer->last();
$mark = $buffer->mark();
$since = $buffer->since($mark);

Everything that hits the global or scoped handlers is recorded here, including silenced notices.

Renderers

ErrorRenderer picks CLI vs HTML by SAPI. JSON is available explicitly.

BackendOutput
CliRendererANSI summary, stack, previous chain, dump CLI blobs
HtmlRendererError page with SourceView panes + HTML dump sections
JsonRenderer$report->jsonString()

Source highlighting and var dumps come from northrook/php-debug — this package wires them in; it does not reimplement them.

Composite construction (optional overrides):

use Northrook\ErrorHandler\ErrorRenderer;
use Northrook\ErrorHandler\Renderer\CliRenderer;
use Northrook\ErrorHandler\Renderer\HtmlRenderer;
use Northrook\ErrorHandler\Renderer\JsonRenderer;

$renderer = new ErrorRenderer(
    cli: new CliRenderer(),
    html: new HtmlRenderer(new ErrorHandlerConfig(debug: true)),
    json: new JsonRenderer(),
);

If a backend renderer itself throws, a dependency-light disaster fallback is printed and the failure is logged at critical.

Typed exception meta

ReportFactory attaches snapshot meta for known contract exceptions (e.g. filesystem path, curl URL). Extend buildMeta() as more types land in contracts.

Demos

From the package root:

php index.php              # list demos
php index.php exception    # uncaught → handle() view
php index.php box          # failsafe probe
php index.php dumps        # context dumps in CLI/HTML
php index.php aggregate    # Noise counts + Action standing list + flush

# Browser
php -S localhost:8080 index.php
# open /?demo=exception
KeyScenario
exceptionUncaught exception → full error view
nestedPrevious-exception chain
warningPHP warning promoted by throwAt
boxBoxed probe; process continues
silencedSilenced notice buffered, then a real failure
jsonreport() + JSON only (no exit)
metaTyped exception meta on the snapshot
dumpsdumps => […] in report context
aggregateRepeated box Noise + Action report; standing list + batched flush

Tests & static analysis

composer test
composer phpstan

Not yet implemented

Deferred (see PLAN.md): SilencePolicy / screamAt, ReportVerbosity Safe redaction, RuntimeMode presets, signature rules, SQLite/file persistence, WTHH disaster file, notification delivery.

northrook/error-handler 适用场景与选型建议

northrook/error-handler 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 07 月 15 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 northrook/error-handler 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 northrook/error-handler 我们能提供哪些服务?
定制开发 / 二次开发

基于 northrook/error-handler 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2026-07-15