在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();
结果:
降龙十八掌! 磊落豪雄 弄清楚:我是谁?