Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
PsrEventDispatcherErrorReporter
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
2 / 2
4
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 report
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of fast-forward/defer.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @copyright Copyright (c) 2026 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
12 * @license   https://opensource.org/licenses/MIT MIT License
13 *
14 * @see       https://github.com/php-fast-forward/defer
15 * @see       https://github.com/php-fast-forward
16 * @see       https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\Defer\ErrorReporter;
20
21use Throwable;
22use FastForward\Defer\ErrorReporterInterface;
23use FastForward\Defer\EventDispatcher\Event\DeferredCallbackFailed;
24use FastForward\Defer\Support\CallbackDescriber;
25use Psr\EventDispatcher\EventDispatcherInterface;
26
27/**
28 * This error reporter implementation MUST dispatch all reported exceptions as events using a PSR-14 compatible event dispatcher.
29 * It SHALL provide a detailed event including the exception, callback description, and arguments.
30 * If the dispatcher throws an exception, this class MUST log the failure using error_log and MUST NOT throw further exceptions.
31 */
32final readonly class PsrEventDispatcherErrorReporter implements ErrorReporterInterface
33{
34    /**
35     * Constructs a new PsrEventDispatcherErrorReporter instance.
36     *
37     * @param EventDispatcherInterface $dispatcher the PSR-14 event dispatcher to use for error reporting
38     */
39    public function __construct(
40        private EventDispatcherInterface $dispatcher,
41    ) {}
42
43    /**
44     * Reports a throwable by dispatching a DeferredCallbackFailed event.
45     *
46     * This method MUST dispatch the exception as an event. If the dispatcher fails, the error MUST be logged.
47     *
48     * @param Throwable $throwable the exception or error to report
49     * @param callable|null $callback the related callback, if available
50     * @param array $args arguments passed to the callback, if any
51     *
52     * @return void
53     */
54    public function report(Throwable $throwable, ?callable $callback = null, array $args = []): void
55    {
56        try {
57            $this->dispatcher->dispatch(
58                new DeferredCallbackFailed(
59                    throwable: $throwable,
60                    callback: null !== $callback ? CallbackDescriber::describe($callback) : null,
61                    arguments: $args,
62                )
63            );
64        } catch (Throwable $reportingFailure) {
65            error_log(
66                \sprintf(
67                    '[%s] Error reporter dispatch failed: %s: %s in %s:%d',
68                    self::class,
69                    $reportingFailure::class,
70                    $reportingFailure->getMessage(),
71                    $reportingFailure->getFile(),
72                    $reportingFailure->getLine()
73                )
74            );
75        }
76    }
77}