PHP7 Trait详解

来源: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();

结果如下

猜你喜欢

转载自www.cnblogs.com/laijinquan/p/10992406.html