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