События в Yii2 — это мощный механизм, который позволяет расширять поведение классов без изменения их кода. Если вы когда-нибудь хотели добавить логирование, отправку уведомлений или другую реакцию на определённые действия, не влезая в чужой код, то события — ваш инструмент. В этой статье мы разберём, как устроены события в Yii2, как их правильно использовать и каких ошибок избегать.
Что такое события и зачем они нужны
Представьте, что вы заказали пиццу. Вы не готовите её сами, но когда курьер звонит в дверь, вы совершаете действие — открываете дверь. В программировании событие — это сигнал о том, что что-то произошло. Класс-источник события (например, модель) сообщает: «Я сохранился!» или «Я удалился!». Другие части программы могут «подписаться» на это событие и выполнить свой код.
В Yii2 события реализованы через механизм Event и EventDispatcher. Основные компоненты: источник события (класс, который наследует yii\base\Component), имя события и обработчик (callback-функция).
Как привязать обработчик к событию
Самый простой способ — использовать метод on() у компонента. Например, у нас есть модель Order, и мы хотим после её сохранения отправить письмо.
// В контроллере или конфигурации
$order = new Order();
$order->on(Order::EVENT_AFTER_INSERT, function ($event) {
// Отправляем письмо
Yii::$app->mailer->compose()
->setTo('client@example.com')
->setSubject('Заказ оформлен')
->send();
});
$order->save();
Здесь EVENT_AFTER_INSERT — это константа, определённая в модели. Yii2 предоставляет множество встроенных событий для ActiveRecord: EVENT_BEFORE_INSERT, EVENT_AFTER_INSERT, EVENT_BEFORE_UPDATE, EVENT_AFTER_UPDATE, EVENT_BEFORE_DELETE, EVENT_AFTER_DELETE и другие.
Если нужно отвязать обработчик, используйте off().
Продвинутый уровень: глобальные события и EventDispatcher
В больших приложениях удобно использовать глобальный диспетчер событий. Yii2 предлагает класс yii\base\Event и компонент yii\base\EventDispatcher (доступен с версии 2.0.14). Он позволяет подписываться на события по имени класса и имени события, не создавая экземпляр.
// Подписка на событие класса Order
Yii::$app->eventDispatcher->on(Order::class, Order::EVENT_AFTER_INSERT, function ($event) {
// Обработчик
});
// Генерация события в модели
$this->trigger(Order::EVENT_AFTER_INSERT);
Такой подход удобен для модулей и расширений: вы не привязываетесь к конкретному экземпляру.
Практические советы и лайфхаки
$event->isValid в обработчиках before-событий, чтобы можно было отменить операцию.
Вот несколько проверенных приёмов:
- Именуйте события осмысленно. Используйте константы, например
EVENT_USER_REGISTERED, а не просто строки. - Не злоупотребляйте событиями. Если логика тесно связана с классом, лучше переопределить метод, а не вешать обработчик.
- Используйте слабую связность. Обработчики не должны зависеть от конкретных экземпляров, если это возможно.
- Документируйте события. В коде класса указывайте, какие события он генерирует и что передаётся в объекте события.
Сравним основные методы для работы с событиями:
| Метод | Где используется | Описание |
|---|---|---|
on() |
Экземпляр компонента | Привязывает обработчик к событию конкретного объекта |
off() |
Экземпляр компонента | Отвязывает обработчик |
trigger() |
Внутри класса | Генерирует событие |
EventDispatcher::on() |
Глобально | Подписка на события класса без экземпляра |
Типичные ошибки и как их избежать
Новички часто наступают на одни и те же грабли. Вот самые распространённые:
- Забывают про порядок выполнения. Обработчики вызываются в порядке добавления. Если важен порядок, указывайте его явно.
- Изменяют данные в after-событиях. После сохранения модели изменения не попадут в базу. Используйте before-события для модификации атрибутов.
- Создают циклические зависимости. Обработчик одного события может генерировать другое, что приведёт к бесконечному циклу. Будьте осторожны.
yii\debug\Panels\EventPanel (входит в yii2-debug). Он покажет все сгенерированные события и их обработчики.
Что в итоге
События в Yii2 — это элегантный способ сделать код расширяемым и слабосвязанным. Используйте их для реакций на действия, но не заменяйте ими основную логику. Помните о порядке обработчиков, документируйте события и не забывайте про отмену операций через $event->isValid. И тогда ваш код станет чище, а жизнь — проще.
Студия WNDER


