Handler.php

PHP

Path: src/Hooks/Handler.php

<?php
namespace mini\Hooks;

use Closure;

/**
 * Event where first non-null response wins
 * Remaining listeners are not called
 *
 * @template TInput The input type to be handled
 * @template TOutput The output type returned by handlers
 * @package mini\Hooks
 */
class Handler extends Dispatcher {

    /** @var list<callable(TInput, mixed...): (TOutput|null)> */
    protected array $listeners = [];

    /**
     * Unsubscribe handler
     *
     * @param callable(TInput, mixed...): (TOutput|null) ...$listeners
     */
    public function off(Closure ...$listeners): void {
        self::filterArrays($listeners, $this->listeners);
    }

    /**
     * Register a handler function
     *
     * @param callable(TInput, mixed...): (TOutput|null) ...$listeners
     */
    public function listen(Closure ...$listeners): void {
        foreach ($listeners as $listener) {
            $this->listeners[] = $listener;
        }
    }

    /**
     * Try each handler in order until one returns non-null
     *
     * @param TInput $data The data to handle
     * @param mixed ...$args Additional context arguments
     * @return TOutput|null First non-null response, or null if no handler matched
     * @throws \Throwable
     */
    public function trigger(mixed $data, mixed ...$args): mixed {
        foreach ($this->listeners as $listener) {
            $result = self::invoke($this, $listener, [$data, ...$args]);
            if ($result !== null) {
                return $result;
            }
        }
        return null;
    }
}