Php что такое behavior

Поведения ¶

Поведения (behaviors) — это экземпляры класса yii\base\Behavior или класса, унаследованного от него. Поведения, также известные как примеси, позволяют расширять функциональность существующих компонентов без необходимости изменения дерева наследования. После прикрепления поведения к компоненту, его методы и свойства «внедряются» в компонент, и становятся доступными так же, как если бы они были объявлены в самом классе компонента. Кроме того, поведение может реагировать на события, создаваемые компонентом, что позволяет тонко настраивать или модифицировать обычное выполнение кода компонента.

Создание поведений ¶

Поведения создаются путем расширения базового класса yii\base\Behavior или его наследников. Например,

namespace app\components; use yii\base\Behavior; class MyBehavior extends Behavior < public $prop1; private $_prop2; public function getProp2() < return $this->_prop2; > public function setProp2($value) < $this->_prop2 = $value; > public function foo() < // . > > 

В приведенном выше примере, объявлен класс поведения app\components\MyBehavior содержащий 2 свойства prop1 и prop2 , и один метод foo() . Обратите внимание, свойство prop2 объявлено с использованием геттера getProp2() и сеттера setProp2() . Это возможно, так как yii\base\Behavior является дочерним классом для yii\base\BaseObject, который предоставляет возможность определения свойств через геттеры и сеттеры.

Так как этот класс является поведением, когда он прикреплён к компоненту, компоненту будут также доступны свойства prop1 и prop2 , а также метод foo() .

Подсказка: Внутри поведения возможно обращаться к компоненту, к которому оно прикреплено, используя свойство yii\base\Behavior::$owner.

Обработка событий компонента ¶

Если поведению требуется реагировать на события компонента, к которому оно прикреплено, то необходимо переопределить метод yii\base\Behavior::events(). Например,

namespace app\components; use yii\db\ActiveRecord; use yii\base\Behavior; class MyBehavior extends Behavior < // . public function events() < return [ ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate', ]; > public function beforeValidate($event) < // . > > 

Метод events() должен возвращать список событий и соответствующих им обработчиков. В приведенном выше примере, объявлено событие EVENT_BEFORE_VALIDATE и его обработчик beforeValidate() . Указать обработчик события, можно одним из следующих способов:

  • строка с именем метода текущего поведения, как в примере выше;
  • массив, содержащий объект или имя класса, и имя метода, например, [$object, ‘methodName’] ;
  • анонимная функция.
Читайте также:  Python sort elements in array

Функция обработчика события должна выглядеть как показано ниже, где $event содержит параметр события. Более детальная информация приведена в разделе События.

Прикрепление поведений ¶

Прикрепить поведение к компоненту можно как статически, так и динамически. На практике чаще используется статическое прикрепление.

Для того чтобы прикрепить поведение статически, необходимо переопределить метод behaviors() компонента, к которому его планируется прикрепить. Метод behaviors() должен возвращать список конфигураций поведений. Конфигурация поведения представляет собой имя класса поведения, либо массив его настроек:

namespace app\models; use yii\db\ActiveRecord; use app\components\MyBehavior; class User extends ActiveRecord < public function behaviors() < return [ // анонимное поведение, прикрепленное по имени класса MyBehavior::class, // именованное поведение, прикрепленное по имени класса 'myBehavior2' => MyBehavior::class, // анонимное поведение, сконфигурированное с использованием массива [ 'class' => MyBehavior::class, 'prop1' => 'value1', 'prop2' => 'value2', ], // именованное поведение, сконфигурированное с использованием массива 'myBehavior4' => [ 'class' => MyBehavior::class, 'prop1' => 'value1', 'prop2' => 'value2', ] ]; > > 

Вы можете связать имя с поведением, указав его в качестве ключа элемента массива, соответствующего конфигурации поведения. В таком случае, поведение называется именованным. В примере выше, два именованных поведения: myBehavior2 и myBehavior4 . Если с поведением не связано имя, такое поведение называется анонимным.

Для того, чтобы прикрепить поведение динамически, необходимо вызвать метод yii\base\Component::attachBehavior() требуемого компонента:

use app\components\MyBehavior; // прикрепляем объект поведения $component->attachBehavior('myBehavior1', new MyBehavior); // прикрепляем по имени класса поведения $component->attachBehavior('myBehavior2', MyBehavior::class); // прикрепляем используя массив конфигураций $component->attachBehavior('myBehavior3', [ 'class' => MyBehavior::class, 'prop1' => 'value1', 'prop2' => 'value2', ]); 

Использование метода yii\base\Component::attachBehaviors() позволяет прикрепить несколько поведений за раз. Например,

$component->attachBehaviors([ 'myBehavior1' => new MyBehavior, // именованное поведение MyBehavior::class, // анонимное поведение ]); 

Так же, прикрепить поведение к компоненту можно через конфигурацию, как показано ниже:

[ 'as myBehavior2' => MyBehavior::class, 'as myBehavior3' => [ 'class' => MyBehavior::class, 'prop1' => 'value1', 'prop2' => 'value2', ], ] 

Более детальная информация приведена в разделе Конфигурации.

Использование поведений ¶

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

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

// публичное свойство "prop1" объявленное в классе поведения echo $component->prop1; $component->prop1 = $value; 

Аналогично, вы можете вызывать публичные методы поведения,

// публичный метод foo() объявленный в классе поведения $component->foo(); 

Обратите внимание, хотя $component не имеет свойства prop1 и метода foo() , они могут быть использованы, как будто являются членами этого класса.

В случае, когда два поведения, имеющие свойства или методы с одинаковыми именами, прикреплены к одному компоненту, преимущество будет у поведения, прикрепленного раньше.

Если при прикреплении поведения к компоненту указано имя, можно обращаться к поведению по этому имени, как показано ниже:

$behavior = $component->getBehavior('myBehavior'); 

Также можно получить все поведения, прикрепленные к компоненту:

$behaviors = $component->getBehaviors(); 

Отвязывание поведений ¶

Чтобы отвязать поведение от компонента, необходимо вызвать метод yii\base\Component::detachBehavior(), указав имя, связанное с поведением:

$component->detachBehavior('myBehavior1'); 

Так же, возможно отвязать все поведения:

Использование поведения TimestampBehavior ¶

В заключении, давайте посмотрим на yii\behaviors\TimestampBehavior — поведение, которое позволяет автоматически обновлять атрибуты с метками времени при сохранении Active Record моделей через insert() , update() или save() .

Для начала, необходимо прикрепить поведение к классу Active Record, в котором это необходимо:

namespace app\models\User; use yii\db\ActiveRecord; use yii\behaviors\TimestampBehavior; class User extends ActiveRecord < // . public function behaviors() < return [ [ 'class' => TimestampBehavior::class, 'attributes' => [ ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'], ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'], ], // если вместо метки времени UNIX используется datetime: // 'value' => new Expression('NOW()'), ], ]; > > 

Конфигурация выше описывает следующее:

  • при вставке новой записи поведение должно присвоить текущую метку времени UNIX атрибутам created_at и updated_at ;
  • при обновлении существующей записи поведение должно присвоить текущую метку времени UNIX атрибуту updated_at .

Примечание: Для того, чтобы приведённая выше конфигурация работала с MySQL, тип created_at и updated_at должен быть int(11) . В нём будет храниться UNIX timestamp.

Теперь, если сохранить объект User , то в его атрибуты created_at и updated_at будут автоматически установлены значения метки времени UNIX на момент сохранения записи:

$user = new User; $user->email = 'test@example.com'; $user->save(); echo $user->created_at; // выведет метку времени на момент сохранения записи 

Поведение TimestampBehavior так же содержит полезный метод touch(), который устанавливает текущую метку времени указанному атрибуту и сохраняет его в базу данных:

Другие поведения ¶

Кроме затронутых выше, есть и другие уже реализованные поведения. Как встроенные, так и сторонние:

  • yii\behaviors\BlameableBehavior — автоматически заполняет указанные атрибуты ID текущего пользователя.
  • yii\behaviors\SluggableBehavior — автоматически заполняет указанные атрибут пригодным для URL текстом, получаемым из другого атрибута.
  • yii\behaviors\AttributeBehavior — автоматически задаёт указанное значение одному или нескольким атрибутам ActiveRecord при срабатывании определённых событий.
  • yii2tech\ar\softdelete\SoftDeleteBehavior — предоставляет методы для «мягкого» удаления и восстановления ActiveRecord. То есть выставляет статус или флаг, который показывает, что запись удалена.
  • yii2tech\ar\position\PositionBehavior — позволяет управлять порядком записей через специальные методы. Информация сохраняется в целочисленном поле.

Сравнение с трейтами ¶

Несмотря на то, что поведения схожи с трейтами тем, что «внедряют» свои свойства и методы в основной класс, они имеют множество отличий. Они оба имеют свои плюсы и минусы, и, скорее, дополняют друг друга, а не заменяют.

Плюсы поведений ¶

Поведения, как и любые другие классы, поддерживают наследование. Трейты можно рассматривать как копипейст на уровне языка. Они наследование не поддерживают.

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

Поведения, в отличие от трейтов, можно настраивать.

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

Конфликты имен свойств и методов поведений, прикрепленных к компоненту, разрешаются на основе порядка их подключения. Конфликты имен, вызванные различными трейтами, требуют ручного переименования конфликтующих свойств или методов.

Плюсы трейтов ¶

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

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

Источник

Оцените статью