PHPackages                             phpdot/error-handler - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Debugging &amp; Profiling](/categories/debugging)
4. /
5. phpdot/error-handler

ActiveLibrary[Debugging &amp; Profiling](/categories/debugging)

phpdot/error-handler
====================

Modern error handler with debug pages, RFC 9457 JSON errors, customizable renderers, solution providers, and PSR-15 middleware.

v0.1.0(1mo ago)00↓90%MITPHPPHP &gt;=8.5

Since Jul 18Pushed 1mo agoCompare

[ Source](https://github.com/phpdot/error-handler)[ Packagist](https://packagist.org/packages/phpdot/error-handler)[ RSS](/packages/phpdot-error-handler/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (27)Versions (7)Used By (0)

phpdot/error-handler
====================

[](#phpdoterror-handler)

A modern error handler for PHP: an HTML debug page in development, clean pages in production, RFC 9457 (`application/problem+json`) responses for JSON clients, and a PSR-15 middleware for framework pipelines. Renderers, solution providers, and context providers are all pluggable, so the same handler adapts from a one-line global setup to a fully wired request pipeline.

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [Architecture](#architecture)
- [Testing](#testing)
- [License](#license)

Requirements
------------

[](#requirements)

RequirementConstraintPHP`>= 8.5``psr/http-factory``^1.0``psr/http-message``^2.0``psr/http-server-middleware``^1.0``psr/log``^3.0`The package depends only on PSR interfaces — bring any PSR-7/PSR-17 implementation (for example [phpdot/http](https://github.com/phpdot/http)) and any PSR-3 logger.

Installation
------------

[](#installation)

```
composer require phpdot/error-handler
```

Usage
-----

[](#usage)

### Global handler

[](#global-handler)

One line registers `set_exception_handler`, `set_error_handler`, and a shutdown handler. Uncaught exceptions render a debug page, PHP warnings and notices become exceptions, and fatal errors are caught on shutdown:

```
use PHPdot\ErrorHandler\ErrorHandler;

ErrorHandler::register('development');
```

Switch to production for clean pages that expose no internals:

```
ErrorHandler::register('production')
    ->setLogger($logger);
```

### PSR-15 middleware

[](#psr-15-middleware)

Wrap the whole application pipeline. The middleware catches any `Throwable`, renders it via the `ExceptionHandler`, and returns a PSR-7 response with the correct status code and a `Content-Type` of `application/problem+json` or `text/html` depending on the request:

```
use PHPdot\ErrorHandler\Middleware\ErrorHandlerMiddleware;

$middleware = new ErrorHandlerMiddleware(
    handler: $exceptionHandler,
    responseFactory: $responseFactory,  // PSR-17
    streamFactory: $streamFactory,      // PSR-17
);

$app->pipe($middleware);
```

### The exception handler directly

[](#the-exception-handler-directly)

`ExceptionHandler` is the core. Call `handle()` to turn a throwable into a rendered string, choosing the renderer from the environment and the request's `Accept` header:

```
use PHPdot\ErrorHandler\ExceptionHandler;
use PHPdot\ErrorHandler\Renderer\HtmlDevRenderer;
use PHPdot\ErrorHandler\Renderer\HtmlProdRenderer;
use PHPdot\ErrorHandler\Renderer\JsonRenderer;

$handler = new ExceptionHandler(
    environment: 'development',
    devRenderer: new HtmlDevRenderer(),
    prodRenderer: new HtmlProdRenderer(),
    jsonRenderer: new JsonRenderer(),
);

$body = $handler->handle($exception, $request);
```

Status codes are derived from the exception: a `getStatusCode()` method is honoured, and `InvalidArgumentException`, `DomainException`, and the rest map to sensible 4xx/5xx codes.

### Solution providers

[](#solution-providers)

A solution provider suggests a fix for a known error. Solutions appear on the debug page and in the JSON `solutions` array. A provider that throws is caught silently — collection never crashes the handler:

```
use PHPdot\ErrorHandler\Contract\SolutionProviderInterface;
use PHPdot\ErrorHandler\Solution\Solution;
use PHPdot\ErrorHandler\Solution\SolutionLink;

final class ClassNotFoundSolution implements SolutionProviderInterface
{
    public function canSolve(\Throwable $exception): bool
    {
        return $exception instanceof \Error
            && str_contains($exception->getMessage(), 'not found');
    }

    public function getSolutions(\Throwable $exception): array
    {
        return [
            new Solution(
                title: 'Class not found',
                description: "Check the namespace and run 'composer dump-autoload'.",
                links: [
                    new SolutionLink('Composer Autoloading', 'https://getcomposer.org/doc/01-basic-usage.md#autoloading'),
                ],
            ),
        ];
    }
}

ErrorHandler::register('development')
    ->addSolutionProvider(new ClassNotFoundSolution());
```

### Context providers

[](#context-providers)

A context provider adds a named tab of data to the debug page. Like solution providers, a throwing provider is caught silently:

```
use PHPdot\ErrorHandler\Contract\ContextProviderInterface;
use Psr\Http\Message\ServerRequestInterface;

final class RouteContextProvider implements ContextProviderInterface
{
    public function getLabel(): string
    {
        return 'Route';
    }

    public function collect(\Throwable $exception, ?ServerRequestInterface $request): array
    {
        return [
            'method' => $request?->getMethod() ?? 'N/A',
            'path' => $request?->getUri()->getPath() ?? 'N/A',
        ];
    }
}
```

Environment variables collected for the debug page are filtered: any key matching a sensitive name (password, secret, token, key, and similar) is masked. Extend the list with `setSensitiveKeys()`.

Architecture
------------

[](#architecture)

A throwable enters through the global handler or the PSR-15 middleware. `ExceptionHandler`assembles an `ErrorContext` — parsed stack trace, filtered environment, provider tabs, and suggested solutions — then hands it to the renderer chosen for the environment and request.

 ```
graph TD
    THROWABLE["Throwableuncaught exception, converted PHP error,or fatal caught on shutdown"]
    ENTRY["Entry pointErrorHandler (global handlers)or ErrorHandlerMiddleware (PSR-15)"]
    HANDLER["ExceptionHandlermaps status code, logs via PSR-3,selects the renderer"]
    CONTEXT["ErrorContextStackTrace + Frames + CodeLines,filtered environment, tabs, solutions"]
    PROVIDERS["ProvidersContextProviderInterface (tabs)SolutionProviderInterface (fixes)"]
    RENDER["RendererInterfaceHtmlDev / HtmlProd / Json (RFC 9457) / PlainText"]
    OUT["Rendered outputstring body, or PSR-7 responsefrom the middleware"]

    THROWABLE --> ENTRY
    ENTRY --> HANDLER
    HANDLER --> CONTEXT
    PROVIDERS --> CONTEXT
    CONTEXT --> RENDER
    RENDER --> OUT
```

      Loading Renderers implement `RendererInterface`, so a custom renderer is a drop-in replacement. The two HTML renderers load a plain PHP template from `templates/`; point their constructor at a different path to fully restyle the page.

Testing
-------

[](#testing)

The package is standalone-testable:

```
composer install
composer test        # PHPUnit
composer analyse     # PHPStan, level max + strict rules
composer cs-check    # PHP-CS-Fixer
composer check       # All three
```

License
-------

[](#license)

MIT.

**This repository is a read-only mirror**, generated by CI from [phpdot/monorepo](https://github.com/phpdot/monorepo). [Pull requests](https://github.com/phpdot/monorepo/pulls)and [issues](https://github.com/phpdot/monorepo/issues) belong in the monorepo.

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance94

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~21 days

Recently: every ~26 days

Total

6

Last Release

33d ago

PHP version history (3 changes)v1.0.0PHP &gt;=8.3

v1.0.4PHP &gt;=8.4

v0.1.0PHP &gt;=8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/62e82421bda4b5d6ba9a47ba6d88caca060dcd0d1a2862f351f3a97657385db0?d=identicon)[phpdot](/maintainers/phpdot)

---

Top Contributors

[![phpdot](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/phpdot "phpdot (6 commits)")[![o3AM](https://avatars.githubusercontent.com/u/252500?v=4)](https://github.com/o3AM "o3AM (1 commits)")

---

Tags

debugexceptionerrorhandlerpsr-15rfc-9457

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phpdot-error-handler/health.svg)

```
[![Health](https://phpackages.com/badges/phpdot-error-handler/health.svg)](https://phpackages.com/packages/phpdot-error-handler)
```

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.9k20.0M1.9k](/packages/cakephp-cakephp)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k21](/packages/tempest-framework)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86337.5k](/packages/flow-php-flow)[typo3/cms-core

TYPO3 CMS Core

3313.6M5.6k](/packages/typo3-cms-core)[spiral/framework

Spiral, High-Performance PHP/Go Framework

2.1k2.3M72](/packages/spiral-framework)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
