Events
Triangle Events связывает обработчики событий с приложением Triangle. Компонент предоставляет support\Events и загрузчик конфигурации event. Он работает синхронно в памяти каждого PHP-процесса: сообщение не передаётся другому worker и не сохраняется для повторной доставки.
Это отдельная реализация от localzet\Events. Не переносите на неё автоматически исправления и гарантии библиотеки Localzet Events.
Подключение
Заголовок раздела «Подключение»composer require triangle/eventsОбъявленные зависимости: PHP ^8.1 и triangle/engine ^8.1. Composer регистрирует пространство имён support из компонента; в приложении проверьте, что другой пакет не подменяет класс support\Events.
Регистрация и вызов
Заголовок раздела «Регистрация и вызов»use support\Events;
$id = Events::on('invoice.created', static function (array $invoice, string $event) { return $invoice['number'];});
$results = Events::emit('invoice.created', ['number' => 'INV-42']);Events::off('invoice.created', $id);Callback получает данные и имя события. Обычный emit возвращает массив результатов. Строгое false останавливает дальнейший вызов. В режиме halt:true возвращается первый результат, отличный от null; если такого нет — null.
Повторная регистрация callback создаёт отдельный ID. Список обработчиков фиксируется перед обходом, поэтому изменение подписок внутри callback влияет на последующий вызов события.
Префиксные подписки
Заголовок раздела «Префиксные подписки»Events::on('invoice.*', $callback) принимает все имена с префиксом invoice. Звёздочка работает только в конце строки; это не регулярное выражение.
В этой реализации off удаляет только точные подписки из eventMap. Префиксную подписку через off снять нельзя. Кроме того, getListeners объединяет числовые ключи через array_merge, поэтому общий порядок точных и префиксных callbacks не следует считать глобальным порядком регистрации.
Для изменяемых подписок долгоживущего процесса используйте точные имена и храните возвращённые ID. Не регистрируйте постоянные callbacks заново на каждый HTTP-запрос.
Загрузка из конфигурации
Заголовок раздела «Загрузка из конфигурации»Bootstrap предназначен для чтения event приложения и плагинов. Start без Server сразу возвращает управление. Install копирует отсутствующий файл конфигурации event.php и не перезаписывает существующий.
В опубликованном Bootstrap::load есть ошибка проверки: is_callable применяется ко всему массиву callbacks вместо текущего callback. Обычный список обработчиков поэтому отклоняется RuntimeException. Для работающей интеграции регистрируйте обработчики напрямую через Events::on в инициализации своего процесса; наличие event.php не означает успешную регистрацию.
Исключения обработчиков
Заголовок раздела «Исключения обработчиков»Emit перехватывает Throwable, добавляет его к результатам и пытается записать в logger. Но статическое типизированное свойство logger не инициализировано: при первом исключении обработчика возможен Error при обращении к нему. Нельзя полагаться на гарантированное продолжение всех listeners после ошибки.
До исправления этого поведения обрабатывайте ожидаемые сбои внутри собственных callbacks и отдельно перехватывайте ошибку вызова emit на границе приложения. Не превращайте перехваченную ошибку критической операции в успешный результат.
support\Events
Заголовок раздела «support\Events»| Метод | Поведение |
|---|---|
on(string $event_name, callable|array $listener): int | Добавить подписку и получить ID |
off(string $event_name, int $id): int | 1 при удалении точной подписки, иначе 0 |
emit(string $event_name, mixed $data, bool $halt = false): mixed | Массив ответов либо первый ненулевой ответ в режиме halt |
getListeners(string $event_name): array | Снимок подходящих точных и префиксных callbacks |
list(): array | Все регистрации с ID, именами и callbacks |
hasListener(string $event_name): bool | Наличие хотя бы одной подходящей подписки |
Под «ненулевым» результатом halt понимается строго не null: false, 0 и пустая строка останавливают обход и возвращаются вызывающему коду.
Для массива [ClassName::class, 'method'] метод on создаёт экземпляр через new ClassName без аргументов, если класс существует. Это не разрешение зависимостей через контейнер; конструктор с обязательными аргументами не подходит. Передавайте уже созданный объект или замыкание, когда нужны зависимости.
Bootstrap
Заголовок раздела «Bootstrap»Triangle\Events\Bootstrap::start(?Server $server = null): void читает event-конфигурацию приложения, приложений плагинов и самих плагинов. При null ничего не делает.
Bootstrap::load(array $events): void ожидает карту event => array callbacks и пытается преобразовать class callbacks через support\Container. Проверка вызываемости содержит описанную в руководстве ошибку; пустая конфигурация допустима, обычный непустой список может не загрузиться.
Install
Заголовок раздела «Install»Triangle\Events\Install::install(): void копирует отсутствующие Config/*.php в config_path приложения. Метод не является миграцией и не обновляет существующую конфигурацию.
Границы процесса
Заголовок раздела «Границы процесса»Все реестры статические и локальны процессу. Нет асинхронного dispatch, сетевого транспорта, persistence, ack/retry или транзакционной связи с базой данных. Для доставки между workers нужен отдельный механизм; emit не является очередью.