AXIAM PHP SDK

ReactorHandlers
in package

FinalYes

Declarative reactor handler binding — CONTRACT.md §22.14.

ReactorServer takes one callable from an event to one answer, which is the right shape for the wire and the wrong shape for the code. A reactor registered for three events opens with a match ($event->event), and that match carries two defects.

The first is cheap: a misspelled event name is a valid string, matches no arm, and is discovered as an event that never fires. The second is not. It is the default arm, which is almost always written ReactorAnswer::allow(). That answers on behalf of code that never ran — the defect §22.10 rule 2 forbids the runtime from committing, relocated into user code where the rule does not reach it. An operator who set fail_closed on a registration has it defeated by a default arm in a file they never read.

This class is the declarative form, in the spirit of §11's RequireAccess: mark the methods, collect them, hand the result to ReactorServer.

final class ClaimsReactor
{
    #[OnReactorEvent(ReactorEvents::TOKEN_PRE_ISSUE)]
    public function enrich(ReactorEvent $event): ReactorAnswer { ... }

    #[OnReactorEvent(ReactorEvents::LOGIN_POST_AUTH)]
    public function screen(ReactorEvent $event): ReactorAnswer { ... }
}

$handlers = ReactorHandlers::of(new ClaimsReactor());
$server   = new ReactorServer($config, $transport, $handlers->handler());

It is pure sugar (§22.14 rule 1): what self::handler() returns is exactly the callable ReactorServer already accepts. It opens nothing, verifies nothing, signs nothing, and does not filter a patch (§22.10 rule 3).

Table of Contents

Methods

bind()  : self
Bind $handler to $event without an attribute.
events()  : array<int, string>
The bound event names, in binding order.
handler()  : callable(ReactorEvent): ReactorAnswer
Compose the bindings into the callable {@see ReactorServer} accepts.
of()  : self
Collect every `#[OnReactorEvent]`-marked public method on $sources.

Methods

bind()

Bind $handler to $event without an attribute.

public bind(string $event, callable(ReactorEvent): ReactorAnswer $handler) : self

The imperative half of the same thing, for handlers that are closures rather than methods. Governed by every §22.14 rule identically.

Parameters
$event : string
$handler : callable(ReactorEvent): ReactorAnswer
Tags
throws
InvalidArgumentException

when $event is outside the §22.5 registry — which is how §22.7's hot-path operations are refused, since they are in no registry row — or is already bound. A second binding is a mistake, never a silent overwrite: which of the two runs is not visible from either one.

Return values
self

events()

The bound event names, in binding order.

public events() : array<int, string>

Pass them to ReactorEvents::defaultFailurePolicy() to see what an unreachable reactor costs — the strictest default among them (§22.8) — derived from the code that handles the events rather than from a restatement of the registration.

Return values
array<int, string>

handler()

Compose the bindings into the callable {@see ReactorServer} accepts.

public handler() : callable(ReactorEvent): ReactorAnswer
Tags
throws
InvalidArgumentException

when nothing is bound. A reactor that handles nothing would consume its queue and abstain from every event, which looks exactly like an outage.

Return values
callable(ReactorEvent): ReactorAnswer

of()

Collect every `#[OnReactorEvent]`-marked public method on $sources.

public static of(object ...$sources) : self

Methods are bound to their instance, so a class-based reactor keeps its state and its constructor-injected collaborators.

Parameters
$sources : object

Objects whose public methods carry the attribute.

Tags
throws
InvalidArgumentException

on an unregistered event name (which is also how §22.7's hot-path operations are refused) or a second binding for an already-bound event.

Return values
self
On this page

Search results