在PHP5.4以前,PHP面向對象須要複用代碼的方式是使用類的繼承。但PHP只支持單繼承,在應對較複雜的業務邏輯中,單繼承就顯得捉襟見肘了。php
如如下應用場景:git
class Person { public function eat() { echo "我是人,我能吃飯<br />"; } } class GuoJing extends Person { public function kungfu() { echo "降龍十八掌!<br />"; } } class XiaoFeng extends Person { public function kungfu() { echo "降龍十八掌!<br />"; } }
Guojing 類 與 XiaoFeng 類都繼承於Person,都有共同的 Kungfu 方法,顯然,咱們不能將這個 Kungfu 方法寫到 Person 類,否則隨便一個路人甲繼承了 Person 類,就擁有了 Kungfu 技能。app
用Trait就能解決此問題:spa
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } class Person { public function eat() { echo "我是人,我能吃飯<br />"; } } class GuoJing extends Person { use Tool; } class XiaoFeng extends Person { use Tool; } $guojing = new GuoJing(); $xiaofeng = new XiaoFeng(); $guojing->kungfu(); $xiaofeng->kungfu();
結果以下:.net
降龍十八掌! 降龍十八掌!
若是Trait類、基類和本類中的方法或屬性同名,最終會以哪一個爲準?code
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } class Person { public function eat() { echo "我是人,我能吃飯<br />"; } public function kungfu() { echo "不是每一個人都會功夫<br />"; } } class GuoJing extends Person { use Tool; public function kungfu() { echo "除了降龍十八掌,我還懂九陰真經!<br />"; } } class XiaoFeng extends Person { use Tool; } $guojing = new GuoJing(); $guojing->kungfu();
結果:對象
除了降龍十八掌,我還懂九陰真經!
註釋本類的 kungfu 方法,得出的結果是:blog
降龍十八掌!
當方法或屬性同名時,當前類中的方法會覆蓋 trait的 方法,而 trait 的方法又覆蓋了基類中的方法。繼承
多個trait有同名的方法/屬性時,會報錯:圖片
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } trait Skill { public function kungfu() { echo "渾厚的內力修爲<br />"; } } class GuoJing { use Tool, Skill; } $guojing = new GuoJing(); $guojing->kungfu();
Fatal error: Trait method kungfu has not been applied, because there are collisions with other trait methods on GuoJing
解決方式:使用insteadof和as來解決衝突
insteadof: 使用某個方法替代另外一個
as: 給方法取別名
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } trait Skill { public function kungfu() { echo "渾厚的內力修爲<br />"; } } class XiaoFeng { use Tool, Skill { Skill::kungfu insteadof Tool; Skill::kungfu as ability; } } $xiaofeng = new XiaoFeng(); $xiaofeng->ability();
渾厚的內力修爲
as關鍵詞能夠修改方法的訪問控制
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } class XiaoFeng { use Tool { Tool::kungfu as protected ability; // 修改方法的訪問控制並起別名 } } $xiaofeng = new XiaoFeng(); $xiaofeng->ability();
報錯:
Fatal error: Uncaught Error: Call to protected method XiaoFeng::ability() from context
Trait也能組合Trait,同時,Trait中支持抽象方法、靜態屬性、靜態方法。
<?php trait Tool { public function kungfu() { echo "降龍十八掌!<br />"; } } trait Feature{ use Tool; abstract public function dream(); public static function character() { echo "磊落豪雄 <br />"; } } class XiaoFeng { use Feature; public function dream() { echo "弄清楚:我是誰? <br />"; } } $xiaofeng = new XiaoFeng(); $xiaofeng->kungfu(); XiaoFeng::character(); $xiaofeng->dream();
結果:
降龍十八掌! 磊落豪雄 弄清楚:我是誰?