代码:
// traittrait traitTest {public function test() {echo "trait test...n";}}// 父类class ParentClass {public function parent() {echo "parent...n";}}// 子类class SubClass extends ParentClass {use traitTest;public function sub() {echo "sub...n";}}$obj = new SubClass;$obj->sub();// 调用子类方法$obj->parent();// 调用父类的方法$obj->test();// 调用trait里的方法
代码和结果截图:
上边的这个例子,子类直接extentds父类,然后又在类内use了trait。这样当前类(子类)就拥有了这三个的全部方法。
子类的sub方法,父类的parent方法,trait的test方法,在子类内都可以直接调用使用。
最基础的使用就这些,看起来是不是也不算难?甚至感觉挺简单的?
那么我们进一步思考一下,类的“继承”难免会出现同名方法,那么这三个里边如果有同名方法,最终会保留哪个?谁的方法会被覆盖呢?
代码:
// traittrait traitTest {public function test() {echo "trait test...n";}public function lookClassName() {echo "trait heren";echo __CLASS__ . "n";}}// 父类class ParentClass {public function parent() {echo "parent...n";}public function lookClassName() {echo __CLASS__ . "n";}}// 子类class SubClass extends ParentClass {use traitTest;public function sub() {echo "sub...n";}public function lookClassName() {echo __CLASS__ . "n";}}$obj = new SubClass;$obj->sub();// 调用子类方法$obj->parent();// 调用父类的方法$obj->test();// 调用trait里的方法$obj->lookClassName();// 调用同名方法
代码和结果截图:
上边这段例子的结果很明显的发现,最终当前类(子类)的方法被调用了,也就是三个里边都有同名方法时,当前类的方法优先。
接下来,注释(删除)当前类的lookClassName()方法。
看上边截图,很明显了,当子类(当前类)没有同名方法,只有父类(基类)和trait中的方法同名时,trait中的方法优先。
结论:当前类(子类)、trait和父类(基类)中有同名方法时“子类高于trait高于父类”。子类的方法会覆盖trait中的方法,而trait的方法会覆盖父类的方法。
前边有提到,trait可以随意组合,随意引用,那么是不是可以同时引入多个trait呢?是。在一个类内,可以同时use多个trait。
// traittrait traitTest {public function test() {echo "trait test...n";}public function lookClassName() {echo "trait heren";echo __CLASS__ . "n";}}trait traitTest2 {public function test2() {echo "trait2 test...n";}public function lookClassName() {echo "trait2 heren";echo __CLASS__ . "n";}}trait traitTest3 {public function test3() {echo "trait3 test...n";}public function lookClassName() {echo "trait3 heren";echo __CLASS__ . "n";}}// 父类class ParentClass {public function parent() {echo "parent...n";}public function lookClassName() {echo __CLASS__ . "n";}}// 子类class SubClass extends ParentClass {use traitTest;use traitTest2, traitTest3;public function sub() {echo "sub...n";}public function lookClassName() {echo __CLASS__ . "n";}}$obj = new SubClass;$obj->sub();// 调用子类方法$obj->parent();// 调用父类的方法$obj->test();// 调用trait里的方法$obj->test2();// 调用trait2里的方法$obj->test3();// 调用trait3里的方法$obj->lookClassName();// 调用同名方法
代码和结果截图:
当需要同时引入多个trait时,只要use trait1, trait2, trait3,在use后边跟多个trait名字即可,多个trait之间用逗号分隔。
当然,也可以分开写,每次use一个trait进来。
此时又有新的问题产生了,如果引入的多个trait都有同名的方法,那么又会是谁优先?谁又被覆盖呢?
代码:
// traittrait traitTest {public function test() {echo "trait test...n";}public function lookClassName() {echo "trait heren";echo __CLASS__ . "n";}}trait traitTest2 {public function test2() {echo "trait2 test...n";}public function lookClassName() {echo "trait2 heren";echo __CLASS__ . "n";}}trait traitTest3 {public function test3() {echo "trait3 test...n";}public function lookClassName() {echo "trait3 heren";echo __CLASS__ . "n";}}// 父类class ParentClass {public function parent() {echo "parent...n";}public function lookClassName() {echo __CLASS__ . "n";}}// 子类class SubClass extends ParentClass {use traitTest, traitTest2, traitTest3 {traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTesttraitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2}public function sub() {echo "sub...n";}// public function lookClassName() {// echo __CLASS__ . "n";// }}$obj = new SubClass;$obj->sub();// 调用子类方法$obj->parent();// 调用父类的方法$obj->test();// 调用trait里的方法$obj->test2();// 调用trait2里的方法$obj->test3();// 调用trait3里的方法$obj->lookClassName();// 调用同名方法
代码和结果截图:
说明(上边的源码和结果是解冲突之后的):
当子类没有(注释或者删除)lookClassName()方法时,调用lookClassName方法,则会调用trait中的方法,因为三个trait中都有同名方法,此时就会发生致命错误(冲突)。
报下边(看截图)的语法错误
此时,就需要解冲突。
解冲突,就需要使用到insteadof关键字,含义是“代替”,就是用哪个代替哪个。
use traitTest, traitTest2, traitTest3 {traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTesttraitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2}
解引入多个trait多个重名方法冲突时,需要在引入时使用insteadof关键字,逐一说明哪个trait的方法代替了哪个trait的(看上边引入代码的注释)。
根据上边引入的代码,是traitTest2的lookClassName代替了traitTest的,然后traitTest3的代替了traitTest2的。
因此,最终输出结果时,调用lookClassName(),输出的就是traitTest3的内容(输出结果看上边最近的“代码和结果截图”)。
当然,也可以换个写法:
use traitTest, traitTest2, traitTest3 {traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2}
这个写法呢,是traitTest2和traitTest3互相代替了,那么此时反而没有traitTest什么事了。这个时候,再调用lookClassName()方法,输出的就是traitTest的lookClassName()方法的内容。
代码和结果截图:
如图,当traitTest2和traitTest3互相代替后,直接输出了traitTest的内容。
到这基本就该结束了,但,有个特殊情况需要考虑一下。
我们之所以会引入多个trait,说明这几个trait里都有想使用的方法,那么非常巧合,其中同名方法正好又都想使用,被代替的方法还能使用么?
解决:我们需要使用到另一个关键字“as”,此关键字的功能,简单理解就是给方法取一个别名。
代码:
// traittrait traitTest {public function test() {echo "trait test...n";}public function lookClassName() {echo "trait heren";echo __CLASS__ . "n";}}trait traitTest2 {public function test2() {echo "trait2 test...n";}public function lookClassName() {echo "trait2 heren";echo __CLASS__ . "n";}}trait traitTest3 {public function test3() {echo "trait3 test...n";}public function lookClassName() {echo "trait3 heren";echo __CLASS__ . "n";}}// 父类class ParentClass {public function parent() {echo "parent...n";}public function lookClassName() {echo __CLASS__ . "n";}}// 子类class SubClass extends ParentClass {use traitTest, traitTest2, traitTest3 {traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2traitTest2::lookClassName as lookClassName2;// traitTest2的lookClassName改别名lookClassName2traitTest3::lookClassName as lookClassName3;// traitTest3的lookClassName改别名lookClassName3}public function sub() {echo "sub...n";}// public function lookClassName() {// echo __CLASS__ . "n";// }}$obj = new SubClass;$obj->sub();// 调用子类方法$obj->parent();// 调用父类的方法$obj->test();// 调用trait里的方法$obj->test2();// 调用trait2里的方法$obj->test3();// 调用trait3里的方法$obj->lookClassName();// 调用同名方法$obj->lookClassName2();// 调用traitTest2更名后的同名方法$obj->lookClassName3();// 调用traitTest3更名后的同名方法
代码和结果截图:
根据上图,就可以看出,当trait2和trait3互相代替,然后同名方法另起别名后,三个trait的同名方法,不再冲突,并且可以分别调用各自原本同名的方法。
到此要说的东西基本都说完了。算是对PHP的trait的一个小小的总结,希望可以帮到需要的朋友。
到此这篇关于PHP中trait的使用和同时引入多个trait时同名方法冲突的处理的文章就介绍到这了,更多相关PHP中trait的使用内容请搜索一聚教程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持一聚教程网!