thesis/dispatcher

Thesis Dispatcher

Maintainers

Package info

github.com/thesis-php/dispatcher

pkg:composer/thesis/dispatcher

Fund package maintenance!

www.tinkoff.ru/cf/5MqZQas2dk7

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-05-06 21:28 UTC

This package is auto-updated.

Last update: 2026-05-06 21:31:49 UTC


README

A lightweight hook dispatcher for PHP. Handlers subscribe to hook classes and are called when those hooks are dispatched.

Installation

composer require thesis/dispatcher

Usage

Subscribing and dispatching

use Thesis\Dispatcher;

final class UserRegistered
{
    public function __construct(
        public readonly string $email,
    ) {}
}

$dispatcher = new Dispatcher();

$dispatcher->subscribe(UserRegistered::class, function (UserRegistered $hook): void {
    echo "Welcome, {$hook->email}!\n";
});

$dispatcher->dispatch(new UserRegistered('user@example.com'));
// Welcome, user@example.com!

Unsubscribing

subscribe() returns an unsubscribe closure:

$unsubscribe = $dispatcher->subscribe(UserRegistered::class, function (): void {
    // ...
});

$unsubscribe(); // removed, will not be called on next dispatch

Unsubscribing from within a handler

The handler receives an unsubscribe closure as its second argument — useful for one-shot handlers:

$dispatcher->subscribe(UserRegistered::class, function (UserRegistered $hook, \Closure $unsubscribe): void {
    sendWelcomeEmail($hook->email);
    $unsubscribe(); // run once, then remove self
});

Multiple handlers

All handlers subscribed to the same hook are called in subscription order:

$dispatcher->subscribe(UserRegistered::class, $sendWelcomeEmail);
$dispatcher->subscribe(UserRegistered::class, $createDefaultSettings);
$dispatcher->subscribe(UserRegistered::class, $notifyAdmins);

$dispatcher->dispatch(new UserRegistered('user@example.com'));
// all three handlers are called in order

Subscribing and unsubscribing during dispatch

It is safe to subscribe or unsubscribe handlers while a hook is being dispatched. Handlers added during dispatch are called in the same pass; unsubscribed ones are skipped:

$dispatcher->subscribe(UserRegistered::class, function (UserRegistered $hook, \Closure $unsubscribe) use ($dispatcher): void {
    echo "first\n";
    $unsubscribe(); // removes itself — skipped on future dispatches, does not affect others

    $dispatcher->subscribe(UserRegistered::class, function (): void {
        echo "third\n"; // added mid-dispatch — still called in this same pass
    });
});

$dispatcher->subscribe(UserRegistered::class, function (): void {
    echo "second\n";
});

$dispatcher->dispatch(new UserRegistered('user@example.com'));
// first
// second
// third

$dispatcher->dispatch(new UserRegistered('user@example.com'));
// second
// third

License

MIT