来源:https://blog.csdn.net/qq_35255775/article/details/80610586
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();
结果如下