在学习laravel的时候总是看到代码中使用了trait,下面结合网上的资料谈谈我的理解加深印象
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait
为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class
组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。
说简单一点就是php是单继承语言,一个类只能继承一个基类,但如果你还想这个类继承其他类的属性或方法,就可以通过trait
解决。
定义格式
trait Name{
public $arr;
public function test(){};
....
}
几乎和类的定义方式一样,但trait
不是类因此trait
不能实例化
调用格式
class ClassName {
use traitName;
}
如下实例
<?php
trait Person{
public function walk(){
echo "person----walk";
}
}
class Animal {
public function eat(){
echo "animal----eat";
}
}
class Dog extends Animal{
use Person;
public function wang(){
echo "wangwangwang";
}
}
$dog1 = new Dog();
$dog1->eat();//animal----eat
$dog1->wang();//wangwangwang
$dog1->walk();//person----walk
Dog继承了Animal中的方法同时还可以调用trait Person中的方法
优先级
测试trait与基类本类方法重名
<?php
trait Person{
public function walk(){
echo "person----walk";
}
public function test(){
echo "person----test";
}
}
class Animal {
public function eat(){
echo "animal----eat";
}
public function walk(){
echo "animal----walk";
}
}
class Dog extends Animal{
use Person;
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
echo "<br />";
$dog1->walk();//person----walk
当trait与基类的方法重名时trait方法会覆盖基类中的方法,当trait中的方法与本来重名时本类中的方法会覆盖trait中的方法即
本类>trait>基类
在trait中定义了属性,基类或本类就不能使用同名属性,反之报错但是在PHP 7.0.0之后只要属性的初始值以及可见性一致的时候会正常运行
<?php
trait Wuman{
public $name = 12;
public function sky(){
echo "wuman----sky";
}
}
class Dog {
// public $name = 'animal';
use Wuman;
public $name = 12;
protected $name = 12;//可见性不一样报错
public $name = 13;//初始值不一样报错
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
多个trait
类里面可以使用多个trait通过逗号分隔即可
<?php
trait Human{
public function show(){
echo "human----show";
}
}
trait Person{
public $name = 'human';
public function walk(){
echo "person----walk";
}
public function test(){
echo "person----test";
}
}
class Animal {
public function eat(){
echo "animal----eat";
}
public function walk(){
echo "animal----walk";
}
}
class Dog extends Animal{
// public $name = 'animal';
use Person,Human;
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
echo "<br />";
$dog1->walk();//person----walk
$dog1->show();//walkhuman----show
但是多个trait难免会遇到方法重名的问题,这里通过insteadof
替换 和 as
取别名的方式解决
<?php
trait Human{
public function show(){
echo "human----show";
}
}
trait Person{
public $name = 'human';
public function walk(){
echo "person----walk";
}
public function test(){
echo "person----test";
}
public function show(){
echo "Person---show";
}
}
class Dog {
// public $name = 'animal';
use Person,Human{
Person::show insteadof Human;
}
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
echo "<br />";
$dog1->walk();//person----walk
echo "<br />";
$dog1->show();//Person----show
上面代码通过insteadof使Human
与Person
的同名方法优先执行Person
所以程序输出person----show,此时如果还想使用Human中的show
方法可通过as
取别名的方式
<?php
trait Human{
public function show(){
echo "human----show";
}
}
trait Person{
public $name = 'human';
public function walk(){
echo "person----walk";
}
public function test(){
echo "person----test";
}
public function show(){
echo "Person---show";
}
}
class Dog {
// public $name = 'animal';
use Person,Human{
Person::show insteadof Human;
Human::show as huShow;
}
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
echo "<br />";
$dog1->walk();//person----walk
echo "<br />";
$dog1->show();//Person----show
echo "<br />";
$dog1->huShow();//human----show
使用 as 语法还可以用来调整方法的访问控制
use Person,Human{
Person::show insteadof Human;
Human::show as private huShow;
}
trait中使用trait
<?php
trait Wuman{
public function sky(){
echo "wuman----sky";
}
}
trait Human{
use Wuman;
public function show(){
echo "human----show";
}
}
trait Person{
public $name = 'human';
public function walk(){
echo "person----walk";
}
public function test(){
echo "person----test";
}
public function show(){
echo "Person---show";
}
}
class Dog {
// public $name = 'animal';
use Person,Human{
Person::show insteadof Human;
Human::show as huShow;
}
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test
echo "<br />";
$dog1->walk();//person----walk
echo "<br />";
$dog1->show();//Person----show
echo "<br />";
$dog1->huShow();//human----show
echo "<br />";
$dog1->sky();//wuman----sky
trait中的抽象类
trait中可以使用抽象类对类施加强制要求
<?php
trait Wuman{
public function sky(){
echo "wuman----sky";
}
abstract public function test();
}
class Dog {
// public $name = 'animal';
use Wuman;
public function wang(){
echo "wangwangwang";
}
public function test(){
echo "Dog----test";
}
}
$dog1 = new Dog();
$dog1->test();//Dog----test