Перейти к содержимому
docs.
WORKSPACE

Документации проектов

Открыть каталог проектов
Localzet ServerАсинхронный PHP-серверTriangleФреймворк и компонентыMIX IDИдентификация и интеграцииHack APIПубличные API хакатонаACNПроект и компонентыUserlay / UserNetПроект и компонентыAxiomПроект и компонентыМесседжинг через почтуПроект и компонентыLWT / JWT / JOSEПроект и компонентыФинансовая аналитика KimaiПроект и компонентыМультипарадигмальная БДПроект и компонентыZorin PlatformПроект и компонентыZorin TrustПроект и компонентыFloraScope / VegwatchПроект и компонентыaegis-qДокументация проектаaevumdbДокументация проектаauditДокументация проектаauto-invest-managerАвтотрейдерcaine-companionДокументация проектаcertbot-cloudflareДокументация проектаClusterLocalzet Server / ClustercmdveilДокументация проектаConsolePHP CLICronБиблиотеки Localzet Serverdata-connectorДокументация проектаdevice-controlDevice Controlenn-projectДокументация проектаEventsБиблиотеки Localzet Server✓flowsintДокументация проектаforgeДокументация проектаHttpClientБиблиотеки Localzet ServerinterpreterСобственный языкinvariaДокументация проектаkeynotesДокументация проектаknotrouteKnotroutelaravel-personal-analyticsДокументация проектаlocalzet-osДокументация проектаmeridianДокументация проектаMQTTБиблиотеки Localzet Servernano-kernelСобственная ОСNoterДокументация проектаpersonal-analyticsДокументация проектаProxyБиблиотеки Localzet ServerPSRБиблиотеки Localzet ServerPSR-7Библиотеки Localzet Serverrschs-monitorДокументация проектаsemsealДокументация проектаshardsealДокументация проектаSocketIOБиблиотеки Localzet ServerSOCKS5Библиотеки Localzet Serverstandalone-analyticsДокументация проектаstatic-php-cliДокументация проектаStorageБиблиотеки Localzet ServersutureДокументация проектаtempoweaveДокументация проектаttsСинтез речиTunnelБиблиотеки Localzet Serverui-kitUI KitvesperДокументация проектаWebAnalyzerWebAnalyzerzorin-access-brokerДокументация проектаzorin-authority-brokerДокументация проектаzorin-authority-sdk-phpДокументация проектаzorin-authority-sdk-pythonДокументация проектаzorin-authority-sdk-tsДокументация проектаzorin-client-intelДокументация проектаzorin-device-core-aospДокументация проектаzorin-host-agentДокументация проектаzorin-native-labДокументация проектаzorin-nodeДокументация проектаzorin-opsДокументация проектаdonstu-python-sdkДокументация проектаfloortraceFloortraceserver-rsLocalzet Server / Cluster
Каталог

Events позволяет нескольким частям PHP-приложения реагировать на одно действие. Например, после сохранения заказа можно обновить метрики и подготовить уведомление, не связывая эти обработчики между собой.

Все обработчики выполняются синхронно в том же процессе, который вызвал emit(). Регистрации хранятся в статических массивах. Отдельного сервера, транспорта и фонового выполнения нет.

Нужен PHP 8.0 или новее. Подключите пакет и Composer autoload:

Окно терминала
composer config repositories.localzet-events vcs https://github.com/localzet/Events
composer require localzet/events:dev-main

В примерах ниже используется localzet\Events. В долгоживущем worker подписки обычно регистрируют при запуске процесса. Каждый процесс имеет собственный набор подписчиков.

use localzet\Events;
$id = Events::on('order.created', static function (array $order, string $event): string {
return $event . ':' . $order['id'];
});
$results = Events::emit('order.created', ['id' => 42]);
echo $results[0]; // order.created:42
Events::off('order.created', $id);

on() возвращает числовой идентификатор регистрации, а не события. Повторная регистрация того же callback создаёт ещё одну подписку. Сохраните ID, если обработчик понадобится удалить.

emit() передаёт каждому callback два аргумента: данные и фактическое имя события. Тип данных библиотека не ограничивает; договорённость о форме payload принадлежит приложению. Если callback требует другой тип, его TypeError будет обработан так же, как остальные исключения слушателей.

$prefix = Events::on('order.*', static function (array $order, string $event): string {
return 'audit:' . $event;
});
$exact = Events::on('order.created', static fn (array $order): string => 'created');
$results = Events::emit('order.created', ['id' => 42]);
// ['audit:order.created', 'created']

Звёздочка работает только в конце имени и означает префикс строки. order.* совпадёт с order.created и order.; order* — ещё и с orders. Звёздочка в середине имени не является шаблоном. Несколько завершающих * удаляются при сохранении префикса; удобнее всегда использовать одну.

Точные и префиксные обработчики объединяются и сортируются по ID регистрации. Поэтому префиксный обработчик, зарегистрированный раньше точного, выполнится первым. Приоритета, связанного с длиной или точностью имени, нет.

В обычном режиме результат emit() — массив значений callback в порядке вызова:

Events::on('permission', static fn () => null);
Events::on('permission', static fn () => false);
Events::on('permission', static fn () => 'not called');
$results = Events::emit('permission', null);
// [null, false]

Только строгое false останавливает распространение. Значения 0, '' и пустой массив не останавливают вызов следующих обработчиков. Побочные эффекты уже выполненных callback не откатываются.

Для поиска первого содержательного ответа передайте третий аргумент true:

$result = Events::emit('permission', null, true);
// false

Этот режим возвращает первый результат, отличный от null. Значение false тоже является ответом. Если слушателей нет или все вернули null, результат — null.

emit() перехватывает любой Throwable внутри callback и продолжает выполнение. В обычном режиме объект исключения попадает в массив результатов:

foreach (Events::emit('order.created', ['id' => 42]) as $result) {
if ($result instanceof Throwable) {
error_log($result->getMessage());
}
}

Сам вызов emit() не выбросит наружу это исключение. В режиме поиска первого ответа исключение пропускается; если дальше нет результата, вернётся null. Для обязательной бизнес-операции, чей отказ должен прервать транзакцию, вызывайте сервис явно либо проверяйте результаты обычного режима.

$id = Events::on('temporary.result', $listener);
try {
Events::emit('temporary.result', $payload);
} finally {
Events::off('temporary.result', $id);
}

off() принимает то же имя регистрации, включая завершающую *. Удаление по фактическому имени события не найдёт префиксную подписку. Удалённый callback больше не удерживается реестром, но ссылки на него могут оставаться в коде приложения.

Перед началом emit() список слушателей копируется в локальную переменную. Подписка или отписка из callback влияет на следующие отправки; текущий список уже выбран. Повторный emit() из обработчика выполняется сразу, поэтому не создавайте цикл, в котором событие безусловно порождает само себя.

В публичном API нет сброса всех регистраций, одноразовой подписки или ограничения рекурсии. Временные подписки следует удалять по сохранённым ID.

<?php
declare(strict_types=1);
use localzet\Events;
require __DIR__ . '/vendor/autoload.php';
$audit = Events::on('invoice.*', static fn (array $invoice, string $name): string => 'audit:' . $name);
$paid = Events::on('invoice.paid', static fn (array $invoice): string => 'paid:' . $invoice['id']);
try {
echo json_encode(Events::emit('invoice.paid', ['id' => 42]), JSON_THROW_ON_ERROR), PHP_EOL;
} finally {
Events::off('invoice.*', $audit);
Events::off('invoice.paid', $paid);
}

Events удобен для синхронных уведомлений внутри одного worker. Для сообщения другому worker нужен отдельный транспорт. Для выполнения после перезапуска, повторных попыток и гарантированного хранения нужна очередь с сохранением сообщений. Медленный callback задерживает отправителя и все последующие обработчики текущего события.

Параметры и возвращаемые значения API

Исходный код · AGPL-3.0