php从以前到现在一直都是单继承的语言,无法同时从两个基类中继承属性和方法,为了解决这个问题,php7出了Trait这个特性(听说这个Trait和Go语言有点类似,具体没学过Go语言) 。
用法:在类中使用use关键字,声明要组合的trait名称。具体的trait声明使用trait关键字,trait不能实例化。
代码如下所示:
<?php
trait Cat{
public $color = 'black';
public function work(){
echo '抓老鼠','<br>';
}
}
class Animal{
public function run(){
echo '跑的很快' ,'<br>';
}
}
class TmoCat extends Animal{
use Cat;
public function color(){
echo $this->color,'<br>';
}
}
$tom = new TmoCat();
$tom->color();
$tom->run();
$tom->work();
结果如下:
测试trait、基类、本类对同名属性和方法的处理
代码如下:
trait Cat{ public $color = 'black'; public function work(){ echo '抓老鼠','<br>'; } public function run(){ echo '猫咪跑的很快','<br>'; } } class Animal{ public $color = 'color'; public function work(){ echo '各司其职','<br>'; } public function run(){ echo '跑的很快' ,'<br>'; } } class TmoCat extends Animal{ use Cat; public $color = 'black-white'; public function work(){ echo $this->color,'<br>'; } } $tom = new TmoCat(); $tom->run(); $tom->work();
当本类或基类中定义了与trait中同样的属性会报错 ,报错信息如下所示,可见基类和本类不能定义与trait中相同的属性。
修改代码:
<?php trait Cat{ public $color = 'black'; public function work(){ echo '抓老鼠','<br>'; } public function run(){ echo '猫咪跑的很快','<br>'; } } class Animal{ public function work(){ echo '各司其职','<br>'; } public function run(){ echo '跑的很快' ,'<br>'; } } class TmoCat extends Animal{ use Cat; public function work(){ echo '抓jack','<br>'; } } $tom = new TmoCat(); $tom->run(); $tom->work();
结果如下:
可见trait能够覆盖基类中的方法,本类能够覆盖trait中的方法。
一个类可以组合多个trait
一个类可以组合多个trait,多个trait之间用逗号隔开。例如 use trait1,trait2;
代码展示:
<?php
trait Cat{
public $color = 'black';
public function work(){
echo '抓老鼠','<br>';
}
}
trait Tiger{
public function eat(){
echo '老虎吃肉','<br>';
}
}
class Animal{
public function run(){
echo '跑的很快' ,'<br>';
}
}
class TmoCat extends Animal{
use Cat,Tiger;
public function color(){
echo $this->color,'<br>';
}
}
$tom = new TmoCat();
$tom->color();
$tom->run();
$tom->work();
$tom->eat();
结果如下:
如果两个triat中有相同的属性和方法,然后有同时use,怎么区分?
当不同的trait中有相同的方法或者属性会产生冲突,解决方法是使用insteadof 或 as进行解决。insteadof是进行替代,as是给它取别名。
代码如下:
<?php trait trait1{ public function drive(){ echo 'This is trait1 drive','<br>'; } public function color(){ echo 'This is trait1 color','<br>'; } } trait trait2{ public function drive(){ echo 'This is trait2 drive','<br>'; } public function color(){ echo 'This is trait2 color','<br>'; } } class Car{ use trait1,trait2{ trait1::drive insteadof trait2; trait1::color insteadof trait2; } } class Bus{ use trait1,trait2{ trait1::drive insteadof trait2; trait1::color insteadof trait2; trait2::color as color2; trait2::drive as drive2; } } class Bike{ use trait1,trait2{ trait1::color insteadof trait2; trait2::color as color1; trait2::drive insteadof trait1; trait1::drive as drive2; } } $car = new Car(); $car->color(); $car->drive(); echo '-------------','<br>'; $bus = new Bus(); $bus->drive(); $bus->color(); $bus->color2(); $bus->drive2(); echo '-------------','<br>'; $bike = new Bike(); $bike->color(); $bike->color1(); $bike->drive(); $bike->drive2();
结果如下:
注意:两个方法或属性相同必须有一个先使用insteadof 替换了另一个的属性如与方法,如果没有替换就将另一个的属性或方法定义别名则会报错。
as还可以修改方法的访问控制
<?php trait Animal{ public function eat(){ echo 'animal can eat'; } } class Cat{ use Animal{ Animal::eat as protected; } } class Dog{ use Animal{ Animal::eat as private eat2; } } $cat = new Cat(); $cat->eat(); //不能正常输出 因为已经给eat修改为protected $dog = new Dog(); $dog->eat(); //可以正常输出 eat的类型并没有修改 $dog->eat2(); //不可以正常输出 eat2的类型为private
trait还可以相互组合,使用抽象方法、静态方法、静态属性
代码如下:
<?php trait Animal{ public static $a_sta = 'Animal静态'; public $a_not_sta = 'Animal非静态'; abstract public function a_name(); public static function a_eat(){ echo 'Animal静态方法','<br>'; } } trait Tiger{ use Animal; public static $t_sta = 'Tiger静态'; public $t_not_sta = 'Tiger非静态'; abstract public function name(); public static function t_eat(){ echo 'Tiger静态方法' ,'<br>'; } } class Cat{ use Tiger; public function name() { // TODO: Implement name() method. echo 'tiger抽象方法','<br>'; } public function a_name() { // TODO: Implement a_name() method. echo 'animal抽象方法','<br>'; } public function show(){ echo 'Animal静态属性:',self::$a_sta ,'<br>'; echo 'Animal非静态属性:',$this->a_not_sta ,'<br>'; echo 'Tiger静态属性:',self::$t_sta ,'<br>'; echo 'Tiger非静态属性:',$this->t_not_sta ,'<br>'; } } $cat = new Cat(); $cat->name(); $cat->a_name(); Cat::a_eat(); Cat::t_eat(); $cat->show();
结果如下:
以上就是我对trait的总结,如有错误请指正;