开发者学堂课程【PHP 进阶教程-由浅入深掌握面向对象开发-第二阶段:trait 优先级】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/712/detail/12704
trait 优先级
主要内容
一、概念
二、示例
三、小结
一、概念
trait 优先级是指 trait 在引入的过程中本身有可能存在类里面的二分法或者类又继承了父类的方法出现同名的成员。继承父类,子类本身有,父类又有,trait里面又有,出现了同名成员。处理同名成员:
1、属性不能同名,同名必须保证同值,不像子类可以重写父类里面的属性一样。trait 里面属性一般偏少,一般方法居多。否则就会报错。
2、同名的方法系统认定为重写,重写就会有优先级的概念。子类 >trait> 父类。子类的优先级比 trait 高,而 trait 又比父类要高。
如果子类、trait、父类都有同名的方法,子类中使用 parent 也只能访问到父类。因为一个类里面既有子类的方法又有 trait 引入的方法,而 trait 引入的方法就相当于在这个类里面。类里面自己的方法与 trait 里面 的方法冲突,所以优先级 trait 子类高,高就会覆盖掉,覆盖就永远被覆盖。除非用 trait 使用别名。
以上就是优先级的概念。
二、示例
1、继承覆盖的问题
在类中继承 trait 的同时父类里面也继承了这个方法。Trait 里面又有一个同名的方法,所以 trait 中将覆盖父类的同名方法。就是说 trait 的优先级比父类高。
具体案例如上图
trait Eat{(有一个 trait)
public function eat Of(有一个方法叫 eat)
Echo 'Eat: :eat'
}
}
class Human{
public function eat Of(Human 类也有一个方法叫 eat)
Echo Human: : eat'
}
}
#子类继承父类同时使用 trait
class Man extends Human{(子类 man 继承了 Human 类,相当于继承了上面的方法,同时 use 了 eat,相当于拿了上面的方法)
use Eat;
}
此时就会同名了。当使用的时候会发现输出的是 trait 里面的方法,因为 trait 的优先级比较高。
l 案例
11trait-extends.php
trait 在继承中的优先权
将上面的代码复制,这几个方法都是很简单的方法,只是为了证明同名。同名之后,这样是看不出的,只能调用。
$m=new man
$m 调用 eat 方法。访问 11trait-extends.php
刷新之后出现的是 eat::eat
说明上面的优先级高于父类优先级。
(1)如果此时存在这种情况,子类又需要父类这个方法,用了 trait 就相当于方法写到了上面,类似子类重写父类方法又要用父类,此时需要加 parent。所以这个解决方案在 trait 里面使用 parent。
#访问父类被重写
Parent::eat();
刷新,确实访问了 human。
eat 是为了写 man、women、animal 之间存在的共同问题,或者 monkey 共同的东西。抽离出来。
(2)如何知道访问 parent?
Trait 是自己写的,写 trait 是因为抽离出来发现有这个问题。在写这个的时候会意识到可能会出现重写的问题。可以重复使用它。
或者子类里面写上重写父类的方法去调用它。当然这个是后面讲的子类里面又出现同名的问题。去访问父类就可以了。
以上只是 trait 与父类同名的问题.
2、如果子类同时与 trait、父类同名,访问的是子类的,因为子类的优先级最高。
#子类同名方法(重写)
Public function eat
Echo“man::eat”
刷新:man::eat 最高级
#类本身的优先级最高,因为有时候不一定trait一定在子类用,有可能是 human 直接引入进来,没有父类的情况。所以类本身的优先级最高,其次是 trait 再次是父类。
如果在代码中加上 parent 关键字:parent::eat();他访问的是 trait 还是父类呢?
发现访问的是父类。
Use 的 trait 是把:
Public function eat(){
#优先级高于父类优先级
#访问父类被重写方法
Parent::eat();
Echo‘Eat::eat’;
写到 use eat 后。
那么自己定义的方法就会覆盖原来的方法,这种覆盖是不可逆的,就是没了。相当于上面的方法是没用的。
这时再次调用 eat 的时候,parent 访问的是父类,trait 不是父类。所以 parent 访问的是 human。那么此时又想要使用 eat 怎么办?
子类和父类的关系已经十分融洽了。Trait 已经被抛弃了,可以使用别名。别名可以保证这个方法被用。以上就是灵活性。
三、小结
1、trait 在引入的过程中有可能参与到类的继承关系中去,参与进去之后就会出现同名被覆盖的问题,这种覆盖就理解为重写。重写就会有优先级的问题。优先级子类高于 trait 高于父类。就近原则。
2、重写的方法,想要访问父类方法,只需要使用 parent 关键字就可以了。如果是trait 重写到父类的,直接在 trait 的方法中使用 parent。
如果是子类想要访问父类,子类重写,就在子类里面使用 parent。
如果子类里面还要保证既重写了父类的 parent 又用它,同时还要保证 trait 里面也用。对 trait 里面的方法使用别名,否则永远都用不到。
3、一般情况下不会出现子类、trait 和父类同时拥有同名方法的可能性,因为这样引入 trait 没有任何含义,trait 里面还有别的需要用的,但是引入进来出现了冲突,这种冲突通常使用别名的方式做这种修改,通常会用别名来处理。这就是 trait的优先级。