# 行為
行為是 yii\base\Behavior 或其子類的實例。行為,也稱為?[mixins](http://en.wikipedia.org/wiki/Mixin),可以無須改變類繼承關系即可增強一個已有的 yii\base\Component 類功能。當行為附加到組件后,它將“注入”它的方法和屬性到組件,然后可以像訪問組件內定義的方法和屬性一樣訪問它們。此外,行為通過組件能響應被觸發的[事件](http://www.yiichina.com/doc/guide/2.0/basic-events),從而自定義或調整組件正常執行的代碼。
## 定義行為
要定義行為,通過繼承 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()`?定義的。能這樣用是因為 yii\base\Object 是 yii\base\Behavior 的祖先類,此祖先類支持用 getter 和 setter 方法定義[屬性](http://www.yiichina.com/doc/guide/2.0/basic-properties)
> 提示:在行為內部可以通過 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)
{
// 處理器方法邏輯
}
}
~~~
yii\base\Behavior::events() 方法返回事件列表和相應的處理器。上例聲明了 yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE 事件和它的處理器?`beforeValidate()`?。當指定一個事件處理器時,要使用以下格式之一:
* 指向行為類的方法名的字符串,如上例所示;
* 對象或類名和方法名的數組,如?`[$object, 'methodName']`;
* 匿名方法。
處理器的格式如下,其中?`$event`?指向事件參數。關于事件的更多細節請參考[事件](http://www.yiichina.com/doc/guide/2.0/basic-events):
~~~
function ($event) {
}
~~~
## 附加行為
可以靜態或動態地附加行為到yii\base\Component。前者在實踐中更常見。
要靜態附加行為,覆寫行為要附加的組件類的 yii\base\Component::behaviors() 方法即可。yii\base\Component::behaviors() 方法應該返回行為[配置](http://www.yiichina.com/doc/guide/2.0/basic-configs)列表。每個行為配置可以是行為類名也可以是配置數組。如:
~~~
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// 匿名行為,只有行為類名
MyBehavior::className(),
// 命名行為,只有行為類名
'myBehavior2' => MyBehavior::className(),
// 匿名行為,配置數組
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// 命名行為,配置數組
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
~~~
通過指定行為配置數組相應的鍵可以給行為關聯一個名稱。這種行為稱為**命名行為**。上例中,有兩個命名行為:`myBehavior2`?和`myBehavior4`?。如果行為沒有指定名稱就是**匿名行為**。
要動態附加行為,在對應組件里調用 yii\base\Component::attachBehavior() 方法即可,如:
~~~
use app\components\MyBehavior;
// 附加行為對象
$component->attachBehavior('myBehavior1', new MyBehavior);
// 附加行為類
$component->attachBehavior('myBehavior2', MyBehavior::className());
// 附加配置數組
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
~~~
可以通過 yii\base\Component::attachBehaviors() 方法一次附加多個行為:
~~~
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 命名行為
MyBehavior::className(), // 匿名行為
]);
~~~
還可以通過[配置](http://www.yiichina.com/doc/guide/2.0/concept-configurations)去附加行為:
~~~
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
~~~
詳情請參考[配置](http://www.yiichina.com/doc/guide/2.0/concept-configurations#configuration-format)章節。
## 使用行為
使用行為,必須像前文描述的一樣先把它附加到 yii\base\Component 類或其子類。一旦行為附加到組件,就可以直接使用它。
行為附加到組件后,可以通過組件訪問一個行為的**公共**成員變量或 getter 和 setter 方法定義的[屬性](http://www.yiichina.com/doc/guide/2.0/concept-properties):
~~~
// "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');
~~~
也可以移除**全部**行為:
~~~
$component->detachBehaviors();
~~~
## 使用?`TimestampBehavior`
最后以 yii\behaviors\TimestampBehavior 的講解來結尾,這個行為支持在 yii\db\ActiveRecord 存儲時自動更新它的時間戳屬性。
首先,附加這個行為到計劃使用該行為的 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'],
],
],
];
}
}
~~~
以上指定的行為數組:
* 當記錄插入時,行為將當前時間戳賦值給?`created_at`?和?`updated_at`?屬性;
* 當記錄更新時,行為將當前時間戳賦值給?`updated_at`?屬性。
保存?`User`?對象,將會發現它的?`created_at`?和?`updated_at`?屬性自動填充了當前時間戳:
~~~
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // 顯示當前時間戳
~~~
yii\behaviors\TimestampBehavior 行為還提供了一個有用的方法 yii\behaviors\TimestampBehavior::touch(),這個方法能將當前時間戳賦值給指定屬性并保存到數據庫:
~~~
$user->touch('login_time');
~~~
## 與 PHP traits 的比較
盡管行為在 "注入" 屬性和方法到主類方面類似于?[traits](http://www.php.net/traits)?,它們在很多方面卻不相同。如上所述,它們各有利弊。它們更像是互補的而不是相互替代。
### 行為的優勢
行為類像普通類支持繼承。另一方面,traits 可以視為 PHP 語言支持的復制粘貼功能,它不支持繼承。
行為無須修改組件類就可動態附加到組件或移除。要使用 traits,必須修改使用它的類。
行為是可配置的而 traits 不能。
行為以響應事件來自定義組件的代碼執行。
當不同行為附加到同一組件產生命名沖突時,這個沖突通過先附加行為的優先權自動解決。而由不同 traits 引發的命名沖突需要通過手工重命名沖突屬性或方法來解決。
### traits 的優勢
traits 比起行為更高效,因為行為是對象,消耗時間和內存。
IDE 對 traits 更友好,因為它們是語言結構。
- 介紹(Introduction)
- 關于 Yii(About Yii)
- 從 Yii 1.1 升級(Upgrading from Version 1.1)
- 入門(Getting Started)
- 安裝 Yii(Installing Yii)
- 運行應用(Running Applications)
- 第一次問候(Saying Hello)
- 使用 Forms(Working with Forms)
- 玩轉 Databases(Working with Databases)
- 用 Gii 生成代碼(Generating Code with Gii)
- 更上一層樓(Looking Ahead)
- 應用結構(Application Structure)
- 結構概述(Overview)
- 入口腳本(Entry Scripts)
- 應用(Applications)
- 應用組件(Application Components)
- 控制器(Controllers)
- 模型(Models)
- 視圖(Views)
- 模塊(Modules)
- 過濾器(Filters)
- 小部件(Widgets)
- 前端資源(Assets)
- 擴展(Extensions)
- 請求處理(Handling Requests)
- 運行概述(Overview)
- 引導(Bootstrapping)
- 路由引導與創建 URL(Routing and URL Creation)
- 請求(Requests)
- 響應(Responses)
- Sessions and Cookies
- 錯誤處理(Handling Errors)
- 日志(Logging)
- 關鍵概念(Key Concepts)
- 組件(Components)
- 屬性(Properties)
- 事件(Events)
- 行為(Behaviors)
- 配置(Configurations)
- 別名(Aliases)
- 類自動加載(Class Autoloading)
- 服務定位器(Service Locator)
- 依賴注入容器(Dependency Injection Container)
- 配合數據庫工作(Working with Databases)
- 數據庫訪問(Data Access Objects): 數據庫連接、基本查詢、事務和模式操作
- 查詢生成器(Query Builder): 使用簡單抽象層查詢數據庫
- 活動記錄(Active Record): 活動記錄對象關系映射(ORM),檢索和操作記錄、定義關聯關系
- 數據庫遷移(Migrations): 在團體開發中對你的數據庫使用版本控制
- Sphinx
- Redis
- MongoDB
- ElasticSearch
- 接收用戶數據(Getting Data from Users)
- 創建表單(Creating Forms)
- 輸入驗證(Validating Input)
- 文件上傳(Uploading Files)
- 收集列表輸入(Collecting Tabular Input)
- 多模型同時輸入(Getting Data for Multiple Models)
- 顯示數據(Displaying Data)
- 格式化輸出數據(Data Formatting)
- 分頁(Pagination)
- 排序(Sorting)
- 數據提供器(Data Providers)
- 數據小部件(Data Widgets)
- 操作客戶端腳本(Working with Client Scripts)
- 主題(Theming)
- 安全(Security)
- 認證(Authentication)
- 授權(Authorization)
- 處理密碼(Working with Passwords)
- 客戶端認證(Auth Clients)
- 安全領域的最佳實踐(Best Practices)
- 緩存(Caching)
- 概述(Overview)
- 數據緩存(Data Caching)
- 片段緩存(Fragment Caching)
- 分頁緩存(Page Caching)
- HTTP 緩存(HTTP Caching)
- RESTful Web 服務
- 快速入門(Quick Start)
- 資源(Resources)
- 控制器(Controllers)
- 路由(Routing)
- 格式化響應(Response Formatting)
- 授權驗證(Authentication)
- 速率限制(Rate Limiting)
- 版本化(Versioning)
- 錯誤處理(Error Handling)
- 開發工具(Development Tools)
- 調試工具欄和調試器(Debug Toolbar and Debugger)
- 使用 Gii 生成代碼(Generating Code using Gii)
- TBD 生成 API 文檔(Generating API Documentation)
- 測試(Testing)
- 概述(Overview)
- 搭建測試環境(Testing environment setup)
- 單元測試(Unit Tests)
- 功能測試(Functional Tests)
- 驗收測試(Acceptance Tests)
- 測試夾具(Fixtures)
- 高級專題(Special Topics)
- 高級應用模版(Advanced Project Template)
- 從頭構建自定義模版(Building Application from Scratch)
- 控制臺命令(Console Commands)
- 核心驗證器(Core Validators)
- 國際化(Internationalization)
- 收發郵件(Mailing)
- 性能優化(Performance Tuning)
- 共享主機環境(Shared Hosting Environment)
- 模板引擎(Template Engines)
- 集成第三方代碼(Working with Third-Party Code)
- 小部件(Widgets)
- Bootstrap 小部件(Bootstrap Widgets)
- jQuery UI 小部件(jQuery UI Widgets)
- 助手類(Helpers)
- 助手一覽(Overview)
- Array 助手(ArrayHelper)
- Html 助手(Html)
- Url 助手(Url)