自PHP5.4之前,PHP面向对象需要复用代码的方式是使用类的继承。但PHP只支持单继承,在应对较复杂的业务逻辑中,单继承就显得捉襟见肘了。
trait的使用场景
如以下应用场景:
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 技能。
用Trait就能解决此问题:
<?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();
结果如下:
降龙十八掌!
降龙十八掌!
方法/属性的重写
如果Trait类、基类和本类中的方法或属性同名,最终会以哪个为准?
<?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 方法,得出的结果是:
降龙十八掌!
当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 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();
浑厚的内力修为
trait方法的访问控制
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,同时,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();
结果:
降龙十八掌!
磊落豪雄
弄清楚:我是谁?