PHPackages                             phphd/exception-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. [Utility &amp; Helpers](/categories/utility)
4. /
5. phphd/exception-handler

ActiveSymfony-bundle[Utility &amp; Helpers](/categories/utility)

phphd/exception-handler
=======================

Message Bus Exception Handler

1.1.1(1y ago)17.5k—3.6%MITPHPPHP &gt;=8.1

Since Aug 5Pushed 1y agoCompare

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

READMEChangelog (4)Dependencies (15)Versions (5)Used By (0)

Exception Handler
=================

[](#exception-handler)

🧰 PHP Exception Handler built on top of [Symfony Messenger](https://symfony.com/doc/current/messenger.html) component. Provides middlewares that allow you to easily re-raise exceptions, chain them, or handle with a dedicated handler.

[![Build Status](https://camo.githubusercontent.com/49875b3e9b7e68541712ad70518a6a6f45ab92cec42b78df35a2b0c4d4399835/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f70687068642f657863657074696f6e2d68616e646c65722f63692e79616d6c3f6272616e63683d6d61696e)](https://github.com/phphd/exception-handler/actions?query=branch%3Amain)[![Codecov](https://camo.githubusercontent.com/9a3819aaa090669af8862090446971bfef2b6aaba8253d297e333eb91aae6e14/68747470733a2f2f636f6465636f762e696f2f67682f70687068642f657863657074696f6e2d68616e646c65722f67726170682f62616467652e7376673f746f6b656e3d475a525857595435355a)](https://codecov.io/gh/phphd/exception-handler)[![Psalm coverage](https://camo.githubusercontent.com/bc19c1c6b3301ae45262d698ba572c843606e80bc303f3f511b97e5d6cc77dd5/68747470733a2f2f73686570686572642e6465762f6769746875622f70687068642f657863657074696f6e2d68616e646c65722f636f7665726167652e737667)](https://shepherd.dev/github/phphd/exception-handler)[![Psalm level](https://camo.githubusercontent.com/45fd4a7361866809da5d9fa30cd473b4f11ee2b52c60ad23a4b76d49cd07d39c/68747470733a2f2f73686570686572642e6465762f6769746875622f70687068642f657863657074696f6e2d68616e646c65722f6c6576656c2e737667)](https://shepherd.dev/github/phphd/exception-handler)[![Packagist Downloads](https://camo.githubusercontent.com/be242b17c71e6a875e5a905db5d24b03bdb8cf38166eebc12d5cc2072ca1854a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f70687068642f657863657074696f6e2d68616e646c65722e737667)](https://packagist.org/packages/phphd/exception-handler)[![Licence](https://camo.githubusercontent.com/859da90d358ec11cfb7f51147696487a4c7d6094dcf1d44d109466d7761ee23d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f70687068642f657863657074696f6e2d68616e646c65722e737667)](https://github.com/phphd/exception-handler/blob/main/LICENSE)

Installation 📥
--------------

[](#installation-)

1. Install via composer

    ```
    composer require phphd/exception-handler
    ```
2. Enable the bundle in the `bundles.php`

    ```
    PhPhD\ExceptionHandler\Bundle\PhdExceptionHandlerBundle::class => ['all' => true],
    ```

Configuration ⚒️
----------------

[](#configuration-️)

To leverage features of this bundle, you should add `phd_exception_handler` middleware to the list:

```
framework:
    messenger:
        buses:
            command.bus:
                default_middleware: false
                middleware:
+                   - phd_exception_handler
                    - validation
                    - doctrine_transaction
```

The core principle of exception handling revolves around the idea that exceptions are dispatched to the corresponding bus to be handled. There must be one exception bus per one origin bus.

The exception bus name convention is straightforward: `command.bus` exceptions are forwarded into `command.exception.bus`.

```
framework:
    messenger:
        buses:
            command.exception.bus:
                default_middleware: false
                middleware:
                    - phd_exception_rethrow_unhandled
                    - phd_exception_chaining
                    - phd_exception_result_filter
                    -   handle_message:
                            - true
```

Currently, there are few exception handling middlewares provided.

### Rethrowing unhandled

[](#rethrowing-unhandled)

Middleware: `phd_exception_rethrow_unhandled`

In case if dispatched exception had not been handled it is rethrown back. The exception is considered as handled if handler returns a response, or throws another exception.

### Exception chaining

[](#exception-chaining)

Middleware: `phd_exception_chaining`

Implements automatic exceptions escalation logic with `#[RaiseAs]` attribute.

### Result filter

[](#result-filter)

Middleware: `phd_exception_result_filter`

Filters out all null results of exception handlers.

Usage 🚀
-------

[](#usage-)

### Re-Raising Exceptions

[](#re-raising-exceptions)

The simplest use-case is defining `#[RaiseAs]` attribute on your exception class:

```
use PhPhD\ExceptionHandler\Middleware\Chain\Escalator\RaiseAs;

#[RaiseAs(AccessDeniedHttpException::class, bus: 'api.exception.bus')]
final class NonWhiteListedUserException extends DomainException
{
}
```

In this example, any time `NonWhiteListedUserException` is thrown from an underlying handler, it will be raised as `AccessDeniedHttpException`.

As you can see, there's required attribute bus option. Since some exceptions could be thrown from multiple different contexts (hence, different buses), it is required to explicitly specify the bus from which the particular exception must be raised, so that in other scenarios another exceptions could be escalated:

```
use PhPhD\ExceptionHandler\Middleware\Chain\Escalator\RaiseAs;

#[RaiseAs(ImportLockedHttpException::class, bus: 'api.exception.bus')]
#[RaiseAs(RecoverableMessageHandlingException::class, bus: 'consumer.exception.bus')]
final class ImportLockedException extends RuntimeException
{
}
```

In this example, `ImportLockedException` could be thrown either in http context (`api.bus`), or in the mq consumer context (`consumer.bus`). Therefore, raised exceptions are different.

### Manual Handling

[](#manual-handling)

The exception is dispatched down to your custom handlers, where you could either return a Response, throw a new exception, or just log it and return `null` so that exception will be re-thrown again.

```
#[AsMessageHandler('api.exception.bus')]
final readonly class InventoryExceptionHandler
{
    /** @throws Throwable */
    public function __invoke(InventoryDomainException $exception, InventoryCommand $command): ?Response
    {
        if ($exception instanceof JournalHasUnInventoriedItemException) {
            $data = $this->formatJournalException($exception);

            return new JsonResponse($data, Response::HTTP_BAD_REQUEST);
        }

        if ($exception instanceof StockItemNotVaildatedException) {
            $data = $this->formatItemException($exception, $command->getJournal());

            throw new StockItemNotValidatedHttpException($data, $exception);
        }

        return null;
    }
}
```

If you would like to use the same exception handler for multiple exception buses, you can do so by adding multiple `#[AsMessageHandler]` attributes:

```
#[AsMessageHandler(bus: 'command.exception.bus')]
#[AsMessageHandler(bus: 'query.exception.bus')]
final readonly class InventoryExceptionHandler
{
    // ...
}
```

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance41

Moderate activity, may be stable

Popularity26

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~53 days

Total

4

Last Release

492d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/41589422?v=4)[Yevhen Sidelnyk](/maintainers/rela589n)[@rela589n](https://github.com/rela589n)

---

Top Contributors

[![rela589n](https://avatars.githubusercontent.com/u/41589422?v=4)](https://github.com/rela589n "rela589n (8 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/phphd-exception-handler/health.svg)

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

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)[flow-php/etl

PHP ETL - Extract Transform Load - Abstraction

374468.4k51](/packages/flow-php-etl)[codefog/contao-haste

haste extension for Contao Open Source CMS

42650.8k139](/packages/codefog-contao-haste)[symfony/ai-bundle

Integration bundle for Symfony AI components

30282.3k6](/packages/symfony-ai-bundle)

PHPackages © 2026

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