W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
行為是 yii\base\Behavior 或其子類的實(shí)例。行為,也稱為?mixins,可以無須改變類繼承關(guān)系即可增強(qiáng)一個已有的 yii\base\Component 類功能。當(dāng)行為附加到組件后,它將“注入”它的方法和屬性到組件,然后可以像訪問組件內(nèi)定義的方法和屬性一樣訪問它們。此外,行為通過組件能響應(yīng)被觸發(fā)的事件,從而自定義或調(diào)整組件正常執(zhí)行的代碼。
要定義行為,通過繼承 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
?并為要附加行為的組件提供了兩個屬性?prop1
?、?prop2
?和一個方法?foo()
。注意屬性?prop2
?是通過 getter?getProp2()
?和 setter?setProp2()
?定義的。能這樣用是因?yàn)?yii\base\Object 是 yii\base\Behavior 的祖先類,此祖先類支持用 getter 和 setter 方法定義屬性
提示:在行為內(nèi)部可以通過 yii\base\Behavior::owner 屬性訪問行為已附加的組件。
如果要讓行為響應(yīng)對應(yīng)組件的事件觸發(fā),就應(yīng)覆寫 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)
{
// 處理器方法邏輯
}
}
yii\base\Behavior::events() 方法返回事件列表和相應(yīng)的處理器。上例聲明了 yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE 事件和它的處理器?beforeValidate()
?。當(dāng)指定一個事件處理器時,要使用以下格式之一:
[$object, 'methodName']
;處理器的格式如下,其中?$event
?指向事件參數(shù)。關(guān)于事件的更多細(xì)節(jié)請參考事件:
function ($event) {
}
可以靜態(tài)或動態(tài)地附加行為到y(tǒng)ii\base\Component。前者在實(shí)踐中更常見。
要靜態(tài)附加行為,覆寫行為要附加的組件類的 yii\base\Component::behaviors() 方法即可。yii\base\Component::behaviors() 方法應(yīng)該返回行為配置列表。每個行為配置可以是行為類名也可以是配置數(shù)組。如:
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// 匿名行為,只有行為類名
MyBehavior::className(),
// 命名行為,只有行為類名
'myBehavior2' => MyBehavior::className(),
// 匿名行為,配置數(shù)組
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// 命名行為,配置數(shù)組
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
通過指定行為配置數(shù)組相應(yīng)的鍵可以給行為關(guān)聯(lián)一個名稱。這種行為稱為命名行為。上例中,有兩個命名行為:myBehavior2
?和myBehavior4
?。如果行為沒有指定名稱就是匿名行為。
要動態(tài)附加行為,在對應(yīng)組件里調(diào)用 yii\base\Component::attachBehavior() 方法即可,如:
use app\components\MyBehavior;
// 附加行為對象
$component->attachBehavior('myBehavior1', new MyBehavior);
// 附加行為類
$component->attachBehavior('myBehavior2', MyBehavior::className());
// 附加配置數(shù)組
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
可以通過 yii\base\Component::attachBehaviors() 方法一次附加多個行為:
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 命名行為
MyBehavior::className(), // 匿名行為
]);
還可以通過配置去附加行為:
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
詳情請參考配置章節(jié)。
使用行為,必須像前文描述的一樣先把它附加到 yii\base\Component 類或其子類。一旦行為附加到組件,就可以直接使用它。
行為附加到組件后,可以通過組件訪問一個行為的公共成員變量或 getter 和 setter 方法定義的屬性:
// "prop1" 是定義在行為類的屬性
echo $component->prop1;
$component->prop1 = $value;
類似地也可以調(diào)用行為的公共方法:
// foo() 是定義在行為類的公共方法
$component->foo();
如你所見,盡管?$component
?未定義?prop1
?和?foo()
?,它們用起來也像組件自己定義的一樣。
如果兩個行為都定義了一樣的屬性或方法,并且它們都附加到同一個組件,那么首先附加上的行為在屬性或方法被訪問時有優(yōu)先權(quán)。
附加行為到組件時的命名行為,可以使用這個名稱來訪問行為對象,如下所示:
$behavior = $component->getBehavior('myBehavior');
也能獲取附加到這個組件的所有行為:
$behaviors = $component->getBehaviors();
要移除行為,可以調(diào)用 yii\base\Component::detachBehavior() 方法用行為相關(guān)聯(lián)的名字實(shí)現(xiàn):
$component->detachBehavior('myBehavior1');
也可以移除全部行為:
$component->detachBehaviors();
TimestampBehavior
最后以 yii\behaviors\TimestampBehavior 的講解來結(jié)尾,這個行為支持在 yii\db\ActiveRecord 存儲時自動更新它的時間戳屬性。
首先,附加這個行為到計(jì)劃使用該行為的 yii\db\ActiveRecord 類:
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
];
}
}
以上指定的行為數(shù)組:
created_at
?和?updated_at
?屬性;updated_at
?屬性。保存?User
?對象,將會發(fā)現(xiàn)它的?created_at
?和?updated_at
?屬性自動填充了當(dāng)前時間戳:
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // 顯示當(dāng)前時間戳
yii\behaviors\TimestampBehavior 行為還提供了一個有用的方法 yii\behaviors\TimestampBehavior::touch(),這個方法能將當(dāng)前時間戳賦值給指定屬性并保存到數(shù)據(jù)庫:
$user->touch('login_time');
盡管行為在 "注入" 屬性和方法到主類方面類似于?traits?,它們在很多方面卻不相同。如上所述,它們各有利弊。它們更像是互補(bǔ)的而不是相互替代。
行為類像普通類支持繼承。另一方面,traits 可以視為 PHP 語言支持的復(fù)制粘貼功能,它不支持繼承。
行為無須修改組件類就可動態(tài)附加到組件或移除。要使用 traits,必須修改使用它的類。
行為是可配置的而 traits 不能。
行為以響應(yīng)事件來自定義組件的代碼執(zhí)行。
當(dāng)不同行為附加到同一組件產(chǎn)生命名沖突時,這個沖突通過先附加行為的優(yōu)先權(quán)自動解決。而由不同 traits 引發(fā)的命名沖突需要通過手工重命名沖突屬性或方法來解決。
traits 比起行為更高效,因?yàn)樾袨槭菍ο螅臅r間和內(nèi)存。
IDE 對 traits 更友好,因?yàn)樗鼈兪钦Z言結(jié)構(gòu)。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: