Skip to content

Commit 386426a

Browse files
committed
Add comprehensive documentation for FastForward Defer
- Introduced `error-reporters.rst` detailing the Error Reporter API and built-in implementations. - Added `event-dispatcher.rst` to explain PSR-14 event dispatcher integration and usage. - Created `index.rst` for API reference overview, mapping public classes and interfaces. - Developed `middleware.rst` to describe the DeferMiddleware for PSR-15 request handling. - Added `support.rst` for CallbackDescriber utility documentation. - Established `compatibility.rst` outlining runtime expectations and best practices. - Expanded `examples/index.rst` with a structured learning path for practical usage. - Created `faq.rst` addressing common questions about the library's functionality. - Enhanced `getting-started.rst` with a minimal example and core concepts. - Updated `index.rst` to provide a clearer introduction to the package. - Revised `installation.rst` for clarity on installation steps and requirements. - Added `dependencies.rst` summarizing package dependencies and integrations. - Created `project-links.rst` for easy access to repository and documentation links. - Updated PSR integration documentation for logger and middleware. - Enhanced usage documentation with detailed examples and common pitfalls. - Improved callback describer example to include static and instance methods. Signed-off-by: Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
1 parent be630c8 commit 386426a

27 files changed

Lines changed: 1560 additions & 203 deletions
Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,75 @@
11
Callback Describer
22
==================
33

4-
FastForward Defer includes a utility to describe any PHP callback in a human-readable way.
4+
``CallbackDescriber`` converts a PHP callable into a human-readable string.
5+
Built-in reporters use it so logs and events can tell you which deferred
6+
callback failed.
7+
8+
Why it exists
9+
-------------
10+
11+
Without a helper like this, generic error reporters would only know that "some
12+
callable" failed. ``CallbackDescriber`` adds context such as:
13+
14+
- the function name
15+
- the class and method
16+
- the closure source file and line
17+
- whether the callback was an invokable object
18+
19+
Supported callable shapes
20+
-------------------------
21+
22+
- String function names such as ``'strlen'``
23+
- Array callables such as ``[SomeClass::class, 'handle']``
24+
- Closures
25+
- First-class callables, which are represented as closures
26+
- Invokable objects
527

628
.. code-block:: php
729
830
use FastForward\Defer\Support\CallbackDescriber;
931
10-
$callback = function () {};
11-
echo CallbackDescriber::describe($callback);
32+
final class ExampleInvoker
33+
{
34+
public static function staticHandle(): void {}
1235
13-
This is useful for debugging, logging, or event reporting.
36+
public function handle(): void {}
1437
15-
Supported callback types:
38+
public function __invoke(): void {}
39+
}
1640
17-
- Named functions
18-
- Static methods
19-
- Object methods
20-
- Closures
21-
- Invokable objects
41+
$object = new ExampleInvoker();
42+
43+
$callbacks = [
44+
'strlen',
45+
[ExampleInvoker::class, 'staticHandle'],
46+
[$object, 'handle'],
47+
static fn(): null => null,
48+
ExampleInvoker::staticHandle(...),
49+
$object,
50+
];
51+
52+
foreach ($callbacks as $callback) {
53+
echo CallbackDescriber::describe($callback) . "\n";
54+
}
55+
56+
What to expect from the output
57+
------------------------------
58+
59+
- String functions stay unchanged.
60+
- Array callables become ``Class::method`` or ``Class->method``.
61+
- Closures become ``Closure@/path/to/file.php:line``.
62+
- Invokable objects become ``Class::__invoke``.
63+
64+
One subtle but important detail: first-class callables created with ``...`` are
65+
closures, so they are described as closures, not as ``Class::method``. If you
66+
want method-style output, pass an array callable instead.
67+
68+
Where it is used
69+
----------------
70+
71+
- ``ErrorLogErrorReporter``
72+
- ``PsrLoggerErrorReporter``
73+
- ``PsrEventDispatcherErrorReporter``
74+
75+
See :doc:`../api/support` for the compact API reference.

docs/advanced/error-reporting.rst

Lines changed: 139 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,176 @@
11
Error Reporting
2-
==============
2+
===============
33

4-
FastForward Defer provides robust error handling for deferred callbacks. Errors thrown by callbacks do not interrupt the execution chain; instead, they are reported via a pluggable error reporter.
4+
When a deferred callback throws, ``Defer`` catches that throwable and forwards
5+
it to the configured ``ErrorReporterInterface`` implementation. This keeps
6+
cleanup code from failing silently and lets you choose how much visibility you
7+
want in each environment.
58

6-
Default Behavior
9+
How reporting is configured
10+
---------------------------
11+
12+
Error reporting is configured globally for ``Defer`` through the static
13+
``Defer::setErrorReporter()`` method.
14+
15+
.. code-block:: php
16+
17+
use FastForward\Defer\Defer;
18+
use FastForward\Defer\ErrorReporter\NullErrorReporter;
19+
20+
Defer::setErrorReporter(new NullErrorReporter());
21+
22+
Every new ``Defer`` instance created after that call uses the configured
23+
reporter. Reset to the default ``error_log`` reporter with:
24+
25+
.. code-block:: php
26+
27+
Defer::setErrorReporter(null);
28+
29+
Built-in reporters at a glance
30+
------------------------------
31+
32+
.. list-table::
33+
:header-rows: 1
34+
35+
* - Class
36+
- Purpose
37+
- Good fit
38+
* - ``ErrorLogErrorReporter``
39+
- Writes a readable message to ``error_log()``
40+
- Default behavior and simple production setups
41+
* - ``NullErrorReporter``
42+
- Ignores failures completely
43+
- Tests or flows where cleanup noise must stay silent
44+
* - ``CompositeErrorReporter``
45+
- Sends the same failure to multiple reporters
46+
- Logging plus metrics, logging plus events, and similar fan-out
47+
* - ``PsrLoggerErrorReporter``
48+
- Writes structured context to a PSR-3 logger
49+
- Applications already using Monolog or another PSR-3 implementation
50+
* - ``PsrEventDispatcherErrorReporter``
51+
- Dispatches a ``DeferredCallbackFailed`` event
52+
- Event-driven observability and decoupled listeners
53+
54+
Default behavior
755
----------------
856

9-
By default, errors are reported using PHP's `error_log()`.
57+
If you never call ``Defer::setErrorReporter()``, the library lazily creates an
58+
``ErrorLogErrorReporter`` instance and logs messages like:
59+
60+
- exception class and message
61+
- source file and line
62+
- a readable callback description
1063

11-
Custom Error Reporter
12-
---------------------
64+
Custom reporters
65+
----------------
1366

14-
You MAY provide a custom error reporter by implementing `ErrorReporterInterface`:
67+
You can implement ``ErrorReporterInterface`` to forward failures anywhere you
68+
need.
1569

1670
.. code-block:: php
1771
1872
use FastForward\Defer\Defer;
1973
use FastForward\Defer\ErrorReporterInterface;
74+
use Throwable;
2075
2176
Defer::setErrorReporter(new class implements ErrorReporterInterface {
22-
public function report(Throwable $throwable, ?callable $callback = null, array $args = []): void {
77+
public function report(Throwable $throwable, ?callable $callback = null, array $arguments = []): void
78+
{
2379
echo '[custom reporter] ' . $throwable::class . ': ' . $throwable->getMessage() . "\n";
2480
}
2581
});
2682
83+
Important caveat
84+
----------------
85+
86+
Custom reporters should not throw. ``Defer`` catches the deferred callback
87+
failure, but it does not wrap the reporter call in an extra safety layer. If
88+
your reporter throws, the remaining cleanup chain may stop early.
89+
90+
If you need to defend against fragile reporters, wrap them with
91+
``CompositeErrorReporter`` or use reporters that already guard their own
92+
internal failures.
93+
2794
NullErrorReporter
2895
-----------------
2996

30-
Suppresses all error output:
97+
Use ``NullErrorReporter`` when you intentionally want silent cleanup failures.
3198

3299
.. code-block:: php
33100
34101
use FastForward\Defer\ErrorReporter\NullErrorReporter;
102+
35103
Defer::setErrorReporter(new NullErrorReporter());
36104
37105
CompositeErrorReporter
38106
----------------------
39107

40-
Allows reporting to multiple destinations:
108+
``CompositeErrorReporter`` fans a failure out to multiple reporters. It also
109+
catches failures thrown by one child reporter, logs that failure through
110+
``error_log()``, and keeps reporting to the remaining child reporters.
41111

42112
.. code-block:: php
43113
44114
use FastForward\Defer\ErrorReporter\CompositeErrorReporter;
45115
use FastForward\Defer\ErrorReporter\ErrorLogErrorReporter;
116+
use FastForward\Defer\ErrorReporter\PsrEventDispatcherErrorReporter;
46117
47-
$stdoutReporter = new class implements ErrorReporterInterface {
48-
public function report(Throwable $throwable, ?callable $callback = null, array $args = []): void {
49-
echo '[stdout] ' . $throwable->getMessage() . "\n";
50-
}
51-
};
118+
$reporter = new CompositeErrorReporter(
119+
new ErrorLogErrorReporter(),
120+
new PsrEventDispatcherErrorReporter($dispatcher),
121+
);
122+
123+
if ($reporter->isEmpty()) {
124+
$reporter->add(new ErrorLogErrorReporter());
125+
}
126+
127+
Defer::setErrorReporter($reporter);
128+
129+
The class also implements ``Countable``, which is useful in tests and diagnostic
130+
code.
131+
132+
PSR-3 logger reporting
133+
----------------------
134+
135+
``PsrLoggerErrorReporter`` sends a structured error entry to any
136+
``Psr\Log\LoggerInterface``.
137+
138+
.. code-block:: php
139+
140+
use FastForward\Defer\ErrorReporter\PsrLoggerErrorReporter;
141+
142+
Defer::setErrorReporter(new PsrLoggerErrorReporter($logger));
143+
144+
The context includes:
145+
146+
- ``exception_class``
147+
- ``message``
148+
- ``file``
149+
- ``line``
150+
- ``callback``
151+
- ``callback_arguments``
152+
- ``exception``
153+
154+
Because the reporter delegates directly to your logger, prefer a logger that
155+
does not throw during error handling.
156+
157+
PSR-14 event reporting
158+
----------------------
159+
160+
``PsrEventDispatcherErrorReporter`` dispatches a
161+
``FastForward\Defer\EventDispatcher\Event\DeferredCallbackFailed`` event.
162+
163+
.. code-block:: php
164+
165+
use FastForward\Defer\ErrorReporter\PsrEventDispatcherErrorReporter;
166+
167+
Defer::setErrorReporter(new PsrEventDispatcherErrorReporter($dispatcher));
168+
169+
This reporter is safer than a naïve custom reporter because it catches
170+
dispatcher failures internally and writes them to ``error_log()``.
171+
172+
Related API
173+
-----------
52174

53-
Defer::setErrorReporter(new CompositeErrorReporter(new ErrorLogErrorReporter(), $stdoutReporter));
175+
See :doc:`../api/error-reporters` for class-by-class reference details and
176+
:doc:`../psr/index` for PSR-specific integration examples.

docs/advanced/index.rst

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
Advanced Topics
22
===============
33

4+
These pages cover the parts of ``fast-forward/defer`` that matter once the
5+
basic mental model is already clear: controlling cleanup boundaries, integrating
6+
with applications, customizing error reporting, and understanding utility
7+
classes used by the built-in reporters.
8+
49
.. toctree::
510
:maxdepth: 2
6-
:caption: Advanced
11+
:caption: Advanced:
712

813
usage
914
error-reporting
1015
integrations
1116
middleware
1217
callback-describer
13-
- Do not share instances across scopes
14-
- Prefer short-lived instances
15-
- Avoid long-lived/global usage

0 commit comments

Comments
 (0)