События - это способ автоматического выполнения нужного кода в определенный момент времени. События имеют большую практическую ценность и используются не только в Yii2, но и в JavaScript, в CMS WordPress и тд. В сети хватает теории на счет событий, в этой статье я сделаю акцент на примерах их использования для того, чтобы новичкам было проще во всем разобраться.
События связаны с таким понятием как "поведения", про которые почитать можно тут.

События можно создавать свои, но чаще используют встроенные в фреймворк:

Yii2-события для MVC
Веб-представление, которое наследуется от yii\web\View
EVENT_BEGIN_BODY
EVENT_END_BODY
 
Model
EVENT_AFTER_VALIDATE
EVENT_BEFORE_VALIDATE
 
Module или Controller
EVENT_AFTER_ACTION - afterAction
EVENT_BEFORE_ACTION - beforeAction
 
Компонент представления 
yii\base\View
EVENT_AFTER_RENDER
EVENT_BEFORE_RENDER
EVENT_END_PAGE
EVENT_BEGIN_PAGE
 
Cвязанные с БД
yii\db\BaseActiveRecord
EVENT_INIT
EVENT_AFTER_FIND
EVENT_BEFORE_INSERT (перед сохранением данных в БД)
EVENT_AFTER_INSERT
EVENT_BEFORE_UPDATE
EVENT_AFTER_UPDATE
EVENT_BEFORE_DELETE
EVENT_AFTER_DELETE
yii\db\ActiveQuery
EVENT_INIT
yii\db\Connection
EVENT_AFTER_OPEN (наступает после подключения к БД)
EVENT_BEGIN_TRANSACTION
EVENT_COMMIT_TRANSACTION
EVENT_ROLLBACK_TRANSACTION
 
Yii2-события уровня запросов
yii\base\Application
EVENT_BEFORE_REQUEST - beforeRequest
EVENT_AFTER_REQUEST - afterRequest
yii\web\Response
EVENT_BEFORE_SEND
EVENT_AFTER_SEND
EVENT_AFTER_PREPARE
 
Yii2-события для компонентов по умолчанию
yii\i18n\MessageSource
EVENT_MISSING_TRANSLATION
yii\mail\BaseMailer
EVENT_BEFORE_SEND
EVENT_AFTER_SEND
 
yii\web\User События связанные с авторизацией
EVENT_BEFORE_LOGIN
EVENT_AFTER_LOGIN
EVENT_BEFORE_LOGOUT
EVENT_AFTER_LOGOUT


Привязку событий к определенному объекту/классу можно осуществлять:
  • в методах объектов и классов;
  • в конфигурации приложения.

Установка обработчиков событий в методах объектов и классов.

Для примеров использую экземпляр класса PostController, который наследует от класса Controller. А код примеров рассчитан на выполнение из действия данного контроллера.

Обработчик - глобальная функция
$obj->on(Class::EVENT_HELLO, 'function_name');
Например в контроллере – после выполнения данного действия вызывается функция get_hello() пользовательского компонента «comp» (класс comp подключен в файле config\main.php в массиве components)
$this->on(yii\web\Controller::EVENT_AFTER_ACTION, Yii::$app->comp->get_hello());

Обработчик - метод объекта

$obj->on(Class::EVENT_HELLO, [$object, 'methodName']);
Например в контроллере – после выполнения данного действия вызывается другой метод контроллера fun_test()
$this->on(yii\web\Controller::EVENT_AFTER_ACTION, [$this, 'fun_test']);
    

Обработчик - метод класса

$obj->on(Class::EVENT_HELLO, ['app\components\Bar', 'methodName']);
Например в контроллере – после выполнения действия вызывается метод name() из класса Slug.
$this->on(yii\web\Controller::EVENT_AFTER_ACTION, ['common\behaviors\Slug', 'name']);
    

Обработчик - анонимная функция
$obj->on(Class::EVENT_HELLO, function ($event) {}
Например в контроллере – после выполнения действия меняется значение публичной переменной text.
$this->on(yii\web\Controller::EVENT_AFTER_ACTION, function ($event) {
    if($this->text == 'Привет') $this->text = 'Приветствую!';
});




Установка обработчиков событий в конфигурации приложения.


В конфигурации привязку событий можно указывать 2-мя способами:


'on afterAction' => function () {}
или
'on '. yii\web\Controller::EVENT_AFTER_ACTION => function () {}
Во втором случае нужно явно указывать объект к которому оно привязывается.

Пример события для компонента приложения.
Например компонент 'comp' с классом common\components\Comp:
'comp' => [
    'class' => 'common\components\Comp',
    'age' => 23,
    'on '. \yii\db\ActiveRecord::EVENT_INIT => function ($event) {
    или тоже самое: 'on init' => function ($event) {
    },
],
        
в данном примере класс Comp должен наследоваться от ActiveRecord или дочернего его класса:
class Comp extends \common\models\Post{}
            
тогда событие сработает, т.к. оно срабатывает при самом наследовании (инициализации) от ActiveRecord.

Если нужно использовать событие которое не связано с каким-то компонентом приложения, например событие которое будет срабатывать после выполнения действия любого контроллера добавляем его в массив $config конфигурационного файла:
$config['on afterAction'] = function ($event) {
    \app\components\GoogleAnalytics::collect();
};
Тут, для примера, вызывается статический метод collect класса GoogleAnalytics.


Установка событий до запуска приложения.

Можно назначить разные обработчики событий в процессе начальной загрузки приложения.
Покажу на примере события для действия контроллера.

Можно разместить в массиве retur (не в components) в файле main.php:
'on afterAction' => function () {
      exit('Событие после выполнения действия контроллера.');
  },
            

Или разместить в файле web\index.php сразу после того как приложение будет создано (перед строкой $application->run())
Yii::$app->on('afterAction', function ($event) {
      exit('Событие после выполнения действия контроллера.');
  });
                


События для самого приложения (Yii::$app).

Тут у нас 2 стандартных события Yii2:
EVENT_BEFORE_REQUEST - beforeRequest
EVENT_AFTER_REQUEST - afterRequest


Аналогично разделу выше - можно назначить обработчики событий в процессе начальной загрузки приложения, сразу после того как приложение будет создано. Пример аналогичный, меняется только название действия.

В файле main.php:
'on beforeRequest' => function () {
    exit('Остановка перед запуском приложения.');
},

Или в web\index.php перед строкой $application->run()
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
      exit('Остановка перед запуском приложения.');
  });
    

Порядок обработки событий.

К одному событию можно присоединить несколько обработчиков. При срабатывании события обработчики будут вызываться в том порядке, к котором они присоединялись к событию.
Чтобы запретить в обработчике вызов всех следующих за ним обработчиков, необходимо установить свойство [[yii\base\Event::handled]] параметра $event в true:
$foo->on(Foo::EVENT_HELLO, function ($event) {
      $event->handled = true;
  });
        

Чтобы обработчик присоединился к началу очереди и запускался первым, при вызове [[yii\base\Component::on()]] в качестве четвертого параметра $append следует передать false:
$foo->on(Foo::EVENT_HELLO, function ($event) {
      // ...
  }, $data, false);
            

Отсоединение обработчиков событий.

Для отсоединения обработчика от события используется метод [[yii\base\Component::off()]].
Устанавливается аналогично методу on().

Чтобы отсоединить ВСЕ обработчики от события:
$obj->off(Class::EVENT_HELLO);

$this->off(yii\web\Controller::EVENT_AFTER_ACTION);
            

события yii2

Инициирование событий (создание своих).


События инициируются при вызове метода [[yii\base\Component::trigger()]].
Класс, в котором инициируются события, должен наследовать от [[yii\base\Component]] или потомка этого класса.

Пример.
Создаем свой класс и подключаем его как компонент в файле config\main.php в массиве components
<?php
  namespace common\components;
  use yii\base\Component;
  use yii\base\Event;
  class Comp extends Component
  {
      const EVENT_HELLO = 'hello';
      public function bar()
      {
          $this->trigger(self::EVENT_HELLO); //инициирование события
          /*
           * Основной функционал метода
           */
      }
     public function linking(){
            $this->on(self::EVENT_HELLO, function ($event) {
                    exit('Привет!');
            });
     }       
  }
            
Показанный выше код инициирует событие hello при каждом вызове метода bar(). Событие привязывается в методе linking(). Поэтому вначале должен быть выполнен данный метод.

Использование:
<div>//Привязываем свой обработчик в этом методе
  Yii::$app->comp->linking();</div><div>
  //Вызываем метод который инициирует событие 
  Yii::$app->comp->bar(); //Привет!</div>
            

Привязку события можно производить в любом месте (не нужен метод linking()), например в действии контроллера:
Yii::$app->comp->on(\common\components\Comp::EVENT_HELLO, function ($event) {
    exit('Привет!');
  });
  Yii::$app->comp->bar();
                    

Если нужна привязка для всех объектов данного класса, то удобно применять специальный метод __construct() (добавить в класс) для того, чтобы не вызывать отдельно метод привязывающий событие.
  public function __construct(){
    parent::__construct();
     $this->on(self::EVENT_HELLO, function ($event) {
            exit('Привет!');
     });
  }
                        

Обработчики событий на уровне класса.

В примерах выше, обработчики событий привязывались к определенному объекту (экземпляру класса) и при создании нового экземпляра необходимо было бы привязывать обработчики снова (если не применять специальный метод __construct()).

Если нужно вызывать событие для каждого экземпляра класса, а привязку сделать за его пределами – применяется статический метод [[yii\base\Event::on()]].

Пример раздела «Инициирование событий» при этом будет выглядеть так:

<?php
  namespace common\components;
  use yii\base\Component;
  use yii\base\Event;
  class Comp extends Component
  {
      const EVENT_HELLO = 'hello';
      public function bar()
      {
          $this->trigger(self::EVENT_HELLO); //инициирование события
     /*
      * Основной функционал метода
      */
      }
  }
            

Привязка ко всем экземплярам класса за пределами класса выглядит так:
\yii\base\Event::on(\common\components\Comp::className(), \common\components\Comp::EVENT_HELLO, function ($event) {
    exit('Привет!');
  });
                

Теперь при создании любого экземпляра класса сработает событие при вызове метода его инициирующего.
$new_comp1 = new \common\components\Comp();       
$new_comp1->bar(); //метод выполняющий нужный код + инициирующий событие
$new_comp2 = new \common\components\Comp();       
$new_comp2->bar(); //метод выполняющий нужный код + инициирующий событие
                    

Например, выполним какой-то код перед выполнением любого метода всех контроллеров приложения:
Event::on(Controller::className(), 'beforeAction', function ($event) {
    //нужный код, например вызов метода какого-то объекта
});


Глобальные события.


Преимущество глобальных событий в том, что им не нужен объект, к событию которого бы присоединялся обработчик и объект, с помощью которого бы это событие инициировалось. Практического применения им я пока не придумал.

Для глобальных событий нужен глобально доступный объект-синглтон, например, экземпляр приложения.
//Устанавливаем обработчик события на пользовательский компонент приложения- класс Comp
  Yii::$app->on('comp', function ($event) {
    exit (get_class($event->sender));  // выводит "common\components\Comp"
  });
//Инициируем событие в нужный момент
  Yii::$app->trigger('comp', new \yii\base\Event(['sender' => new \common\components\Comp]));

В обработчиках можно получить доступ к объекту, который инициировал событие, с помощью свойства
$event->sender

Данные примеры составлены лично мной, будут вопросы - задавайте в комментариях.