5 追蹤者

行為

行為是 yii\base\Behavior 或子類別的實例。 行為,也稱為 mixins,讓您可以在不需更改類別繼承結構的情況下,增強現有 component 類別的功能。 將行為附加到元件會將行為的方法和屬性「注入」到元件中,使這些方法和屬性可以像在元件類別本身中定義一樣被存取。 此外,行為可以回應元件觸發的 事件,這使得行為也可以自訂元件的正常程式碼執行。

定義行為

要定義行為,請建立一個類別,該類別繼承 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,它具有兩個屬性 prop1prop2 以及一個方法 foo()。 請注意,屬性 prop2 是透過 getter getProp2() 和 setter setProp2() 定義的。 這是因為 yii\base\Behavior 繼承了 yii\base\BaseObject,因此支援透過 getter 和 setter 定義 屬性

因為這個類別是一個行為,當它被附加到一個元件時,該元件也將具有 prop1prop2 屬性以及 foo() 方法。

提示: 在行為中,您可以透過 yii\base\Behavior::$owner 屬性存取附加行為的元件。

注意: 如果行為的 yii\base\Behavior::__get() 和/或 yii\base\Behavior::__set() 方法被覆寫,您也需要覆寫 yii\base\Behavior::canGetProperty() 和/或 yii\base\Behavior::canSetProperty()

處理元件事件

如果行為需要回應其附加到的元件所觸發的事件,則應覆寫 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']
  • 一個匿名函式

事件處理常式的簽章應如下所示,其中 $event 指的是事件參數。 有關事件的更多詳細資訊,請參閱 事件 章節。

function ($event) {
}

附加行為

您可以靜態或動態地將行為附加到 元件。 後者在實務中更常見。

要靜態地附加行為,請覆寫要附加行為的元件類別的 behaviors() 方法。 behaviors() 方法應傳回行為 配置 的清單。 每個行為配置可以是行為類別名稱或配置陣列

namespace app\models;

use yii\db\ActiveRecord;
use app\components\MyBehavior;

class User extends ActiveRecord
{
    public function behaviors()
    {
        return [
            // anonymous behavior, behavior class name only
            MyBehavior::class,

            // named behavior, behavior class name only
            'myBehavior2' => MyBehavior::class,

            // anonymous behavior, configuration array
            [
                'class' => MyBehavior::class,
                'prop1' => 'value1',
                'prop2' => 'value2',
            ],

            // named behavior, configuration array
            'myBehavior4' => [
                'class' => MyBehavior::class,
                'prop1' => 'value1',
                'prop2' => 'value2',
            ]
        ];
    }
}

您可以透過指定對應於行為配置的陣列鍵來將名稱與行為關聯。 在這種情況下,該行為稱為具名行為。 在上面的範例中,有兩個具名行為:myBehavior2myBehavior4。 如果行為未與名稱關聯,則稱為匿名行為

要動態地附加行為,請呼叫要附加行為的元件的 yii\base\Component::attachBehavior() 方法

use app\components\MyBehavior;

// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior());

// attach a behavior class
$component->attachBehavior('myBehavior2', MyBehavior::class);

// attach a configuration array
$component->attachBehavior('myBehavior3', [
    'class' => MyBehavior::class,
    'prop1' => 'value1',
    'prop2' => 'value2',
]);

您可以使用 yii\base\Component::attachBehaviors() 方法一次附加多個行為

$component->attachBehaviors([
    'myBehavior1' => new MyBehavior(), // a named behavior
    MyBehavior::class,                 // an anonymous behavior
]);

您也可以透過 配置 附加行為,如下所示

[
    'as myBehavior2' => MyBehavior::class,

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

有關更多詳細資訊,請參閱 配置 章節。

使用行為

要使用行為,首先依照上述說明將其附加到 元件。 一旦行為附加到元件,其使用方式就很簡單。

您可以透過附加行為的元件存取行為的公有成員變數或 getter 和/或 setter 定義的 屬性

// "prop1" is a property defined in the behavior class
echo $component->prop1;
$component->prop1 = $value;

您也可以類似地呼叫行為的公有方法

// foo() is a public method defined in the behavior class
$component->foo();

如您所見,雖然 $component 未定義 prop1foo(),但由於附加的行為,它們可以像元件定義的一部分一樣使用。

如果兩個行為定義了相同的屬性或方法,並且它們都附加到同一個元件,則首先附加到元件的行為在存取屬性或方法時將優先。

行為可以在附加到元件時與名稱關聯。 如果是這種情況,您可以使用名稱存取行為物件

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

您也可以取得附加到元件的所有行為

$behaviors = $component->getBehaviors();

分離行為

要分離行為,請使用與行為關聯的名稱呼叫 yii\base\Component::detachBehavior()

$component->detachBehavior('myBehavior1');

您也可以分離所有行為

$component->detachBehaviors();

使用 TimestampBehavior

總結一下,讓我們看看 yii\behaviors\TimestampBehavior。 此行為支援在每次透過 insert()update()save() 方法儲存模型時自動更新 Active Record 模型的時間戳記屬性。

首先,將此行為附加到您計劃使用的 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'],
                ],
                // if you're using datetime instead of UNIX timestamp:
                // 'value' => new Expression('NOW()'),
            ],
        ];
    }
}

上面的行為配置指定當記錄正在

  • 插入時,行為應將目前的 UNIX 時間戳記指派給 created_atupdated_at 屬性
  • 更新時,行為應將目前的 UNIX 時間戳記指派給 updated_at 屬性

注意: 為了使上述實作能夠與 MySQL 資料庫協同運作,請將欄位 (created_atupdated_at) 宣告為 int(11) 以作為 UNIX 時間戳記。

有了該程式碼,如果您有一個 User 物件並嘗試儲存它,您會發現它的 created_atupdated_at 會自動填入目前的 UNIX 時間戳記

$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at;  // shows the current timestamp

TimestampBehavior 也提供了一個有用的方法 touch(),它會將目前的時間戳記指派給指定的屬性並將其儲存到資料庫

$user->touch('login_time');

其他行為

有幾個內建和外部行為可用

行為與 Traits 的比較

雖然行為與 traits 相似,因為它們都將其屬性和方法「注入」到主要類別中,但它們在許多方面有所不同。 如下所述,它們各有優缺點。 它們更像是彼此的補充,而不是替代品。

使用行為的原因

行為類別與一般類別一樣,支援繼承。 另一方面,Traits 可以被視為語言支援的複製和貼上。 它們不支援繼承。

行為可以動態地附加和分離到元件,而無需修改元件類別。 若要使用 trait,您必須修改使用它的類別的程式碼。

行為是可配置的,而 traits 則不是。

行為可以透過回應元件的事件來自訂元件的程式碼執行。

當附加到同一個元件的不同行為之間可能存在名稱衝突時,衝突會透過優先處理首先附加到元件的行為來自動解決。 由不同 traits 引起的名稱衝突需要手動解決,方法是重新命名受影響的屬性或方法。

使用 Traits 的原因

Traits 比行為有效率得多,因為行為是物件,需要時間和記憶體。

IDE 對 traits 更友善,因為它們是原生語言結構。

發現錯字或您認為此頁面需要改進嗎?
在 github 上編輯 !