Event.php

PHP

Path: src/Hooks/Event.php

<?php
namespace mini\Hooks;

use Closure;

/**
 * Event dispatcher for events that can trigger multiple times
 *
 * @template TPayload The primary payload type passed to listeners
 * @package mini\Hooks
 */
class Event extends Dispatcher {

    /** @var list<callable(TPayload, mixed...): void> */
    protected array $listeners = [];

    /** @var list<callable(TPayload, mixed...): void> */
    protected array $onceListeners = [];

    /**
     * Invoke all event listeners with the provided arguments
     *
     * @param TPayload $payload
     * @param mixed ...$args Additional arguments
     * @throws \Throwable
     */
    public function trigger(mixed ...$args): void {
        $this->invokeAll($this->listeners, ...$args);

        $once = $this->onceListeners;
        $this->onceListeners = [];
        $this->invokeAll($once, ...$args);
    }

    /**
     * Subscribe to this event
     *
     * @param callable(TPayload, mixed...): void ...$listeners
     */
    public function listen(Closure ...$listeners): void {
        foreach ($listeners as $listener) {
            $this->listeners[] = $listener;
        }
    }

    /**
     * Subscribe and auto-unsubscribe after first trigger
     *
     * @param callable(TPayload, mixed...): void ...$listeners
     */
    public function once(Closure ...$listeners): void {
        foreach ($listeners as $listener) {
            $this->onceListeners[] = $listener;
        }
    }

    /**
     * Unsubscribe from this event
     *
     * @param callable(TPayload, mixed...): void ...$listeners
     */
    public function off(Closure ...$listeners): void {
        self::filterArrays(
            $listeners,
            $this->listeners,
            $this->onceListeners,
        );
    }
}