當前位置:
首頁 > 知識 > yii2中行為和Trait的區別

yii2中行為和Trait的區別

這可能是大家最疑問的地方,到底有和不同。

進入我們自己的解釋之前,我先把yii2官方的說法粘貼一份過來,這是一個我們在選擇用行為還是trait的一個標準。

官方的說明

儘管行為在 "注入" 屬性和方法方面類似於 trait ,它們在很多方面卻不相同。如上所述,它們各有利弊。它們更像是互補的而不是相互替代。

行為的優勢

行為類像普通類支持繼承。另一方面,trait 可以視為 PHP 語言支持的複製粘貼功能,它不支持繼承。

行為無須修改組件類就可動態附加到組件或移除。要使用 trait,必須修改使用它的類。

行為是可配置的而 trait 不能。

行為以響應事件來自定義組件的代碼執行。

當不同行為附加到同一組件產生命名衝突時,這個衝突通過先附加行為的優先權自動解決。而由不同 trait 引發的命名衝突需要通過手工重命名衝突屬性或方法來解決。

trait 的優勢

traits 比起行為更高效,因為行為是對象,消耗時間和內存。

IDE 對 trait 更友好,因為它們是語言結構。

行為只能服務於組件類,而 trait 沒有這個限制。

總結一下

通過上面的說明,總結來說就一條:用行為、用行為、用行為。

雖然我們已經會了行為,官方也說你就用行為就行了。但是我們還是有必要了解下traits,它到底是什麼?

traits的注入

首先要說的是traits的目的是解決類只能單繼承的問題,行為也是這個目的,我們在第一篇 前導課 - 什麼是行為? 就已經分析了 。

有一點很重要,就是trait不能被實例化。

我們來舉一個 trait 的例子,讓你知道什麼是trait

traitMouse {public$name = 滑鼠 ;publicfunctionclick(){echo"滑鼠點擊了一下"; }}classComputer{publicfunctionsayName(){echo"我是一台電腦"; }}classMacbookextendsComputer{useMouse;publicfunctionsay(){echo"我是一條有逼格的macbook"; }}

我來解釋一下上面的代碼,Macbook 和 Computer 是繼承關係,Mouse 是一個trait ,Macbook 使用 use 關鍵字將 Mouse 注入到自己體內,此刻 Macbook 的 use 有點像yii2的 behaviors 函數。

接下來看看使用情況

$model=newMacbook ();$model->say();// 我是一條有逼格的macbook$model->sayName();// 我是一台電腦$model->click();// 滑鼠點擊了一下

很高興的是 trait 也同樣注入了 Macbook 類增強了其功能,但是和行為不同是我們必須通過修改 Macbook 類代碼實現,而yii2的行為可以通過動態綁定來實現對 Macbook 類的零修改。關於動態綁定可以參考之前乾貨文章 傳送門

優先順序

這個問題在行為和 trait 中都會存在,當使用它們的類、繼承的類中具有相同成員時誰會被使用?

對於trait,優先順序是來自當前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。

對於行為,優先順序是來自當前類的成員覆蓋了被繼承的方法,而繼承的方法則覆蓋了行為的方法。

沒明白么?那看我的這個圖。

在順序上略有不同。

多個組合成員名稱衝突問題

什麼意思那,就是一個類同時使用了多個 trait 的情況,看下面代碼。

traitMouse {publicfunctionclick(){echo"滑鼠點擊了一下"; }}traitKeyboard{publicfunctionclick(){echo"鍵盤點擊了一下"; }}classMacbook{useMouse,Keyboard;}$model =newMacbook();$model->click();

我們看看結果

很不幸,對於此種情景PHP並沒有給出自動處理方案,直接拋出了致命error。

這個時候我們必須人工參與,使用下面的關鍵詞

insteadof

as

我們來說明下,還是上面的例子

...classMacbook{useMouse,Keyboard{Mouse::clickinsteadofKeyboard; }}$model =newMacbook();$model->click();

結果輸出了 「滑鼠點擊了一下」,因為我們use的時候告訴phpMouse::click insteadof Keyboard,當衝突的時候使用Mouse的click代替Keyboard的同名方法。

當然我們還可以使用別名as,注意as無法替代insteadof,但是它可以讓被替代者以其他的名字運行。

...classMacbook{useMouse,Keyboard{Mouse::clickinsteadofKeyboard; Keyboard::clickaskeyClick; }}$model =newMacbook();$model->click();$model->keyClick();

看看結果

我們解決了衝突。

yii2的多行為成員衝突問題

而對於yii2而言則按照先附加行為的優先權自動解決,並不會產生錯誤,具體如何解決本篇不再重複,可以去看下 揭秘yii2中行為的方法是如何注入到組件類中去的~ 這篇。

當然這種衝突解決方法會將後面的同名函數雪藏,而 trait 則可以將其通過as關鍵詞再次啟動起來。但是這個問題並不大,此種情景我們可以有太多方法解決了。

關於事件

event是個不能忽視的存在,通過前幾篇我們都知道行為+事件可以擁有很多炫酷的注入能力,那麼trait ?

當然也可以,但是會麻煩很多,我來舉個例子。

// @appcomponentsEventTrait.phpnamespaceappcomponents;useappmodelsUser;traitEventTrait {publicfunctioninitEvent(){ User::on(User::EVENT_LOOK_ME,function(){echo"i am event"; }); }}// @appmodelsUser.phpclassUserextendsyiidbActiveRecord{ ...constEVENT_LOOK_ME = event_look_me ;useEventTrait; ...}// 在action中$model =newUser();$model->initEvent();$model->trigger(User::EVENT_LOOK_ME);

雖然也可以實現,但是自然沒有行為來得容易,對代碼的侵入性也太強,不建議這樣用。

其他

當然根據官方還有很多,比如行為可配置等,這些因為前幾篇都已經進行了講解,這裡不再重複。

整體來說,yii2行為和trait 都可以解決單繼承問題,並且也具有很不錯的注入和組合能力,但是在各方面行為和yii2其他模塊整合更好一點,因此推薦用yii2的行為。

不過這不是說你可以放棄 trait 了,記住,行為只能服務於組件類,但是yii2的世界裡還有不是組件類的孩子們,請思考。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 PHP技術大全 的精彩文章:

關於PHP的錯誤機制總結
SecLists-安全測試者的手冊
2017 最新 PHP 框架橫向對比
我的開發工具集們
PHP實現queue數據結構

TAG:PHP技術大全 |

您可能感興趣

細讀Yii2的Response
淺談csrf攻擊以及yii2對其的防範措施