当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

发布:smiling 来源: PHP粉丝网  添加日期:2023-07-12 17:04:31 浏览: 评论:0 

这篇文章主要介绍了PHP中trait的使用和同时引入多个trait时同名方法冲突的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下。

PHP的类是单一继承模式,也就是每个类只能继承一个父类(基类)。

但有时需要引入更多通用(共用)的方法,同时这些方法又不适合集成到基类。

那么这时,就需要使用其他方法来引入这些方法。其中trait,就是方法之一。

trait是PHP5.4之后出现的一种代码复用方法,形式和Class非常相似,同时可以随意组合任意引入。

trait一般在当前类和其同父类(基类)的其他类都需要使用相同方法时,而其父类(基类)又要尽量避免出现这些方法时使用。

甚至有时可能其他关联不是特别大的类(分别继承不同的父类)也可能会使用共同的方法,也可以使用trait的方法。

尽量通俗一点的说一下trait:

trait像类,但不是类,不可以直接使用new关键字创建对象;简单理解是用类的形式,封装一大堆通用(共用)的方法,供其他类引用。

trait和use搭配使用。定义好trait后,“use trait定义的名字;”,就可以直接使用里边定义的一切了,是不是很简单?很方便?

现在知道了trait,接下来就通过代码实例,演示一下trait的具体使用和一些小情况。

一、trait的使用

代码:

  1. // trait 
  2. trait traitTest { 
  3.     public function test() { 
  4.         echo "trait test...\n"
  5.     } 
  6. // 父类 
  7. class ParentClass { 
  8.     public function parent() { 
  9.         echo "parent...\n"
  10.     } 
  11. // 子类 
  12. class SubClass extends ParentClass { 
  13.     use traitTest; 
  14.     public function sub() { 
  15.         echo "sub...\n"
  16.     } 
  17. $obj = new SubClass; 
  18. $obj->sub();// 调用子类方法 
  19. $obj->parent();// 调用父类的方法 
  20. $obj->test();// 调用trait里的方法 

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

上边的这个例子,子类直接extentds父类,然后又在类内use了trait。这样当前类(子类)就拥有了这三个的全部方法。

子类的sub方法,父类的parent方法,trait的test方法,在子类内都可以直接调用使用。

最基础的使用就这些,看起来是不是也不算难?甚至感觉挺简单的?

那么我们进一步思考一下,类的“继承”难免会出现同名方法,那么这三个里边如果有同名方法,最终会保留哪个?谁的方法会被覆盖呢?

二、当父类、子类和trait的方法重名

代码:

  1. // trait 
  2. trait traitTest { 
  3.     public function test() { 
  4.         echo "trait test...\n"
  5.     } 
  6.     public function lookClassName() { 
  7.         echo "trait here\n"
  8.         echo __CLASS__ . "\n"
  9.     } 
  10. // 父类 
  11. class ParentClass { 
  12.     public function parent() { 
  13.         echo "parent...\n"
  14.     } 
  15.     public function lookClassName() { 
  16.         echo __CLASS__ . "\n"
  17.     } 
  18. // 子类 
  19. class SubClass extends ParentClass { 
  20.     use traitTest; 
  21.     public function sub() { 
  22.         echo "sub...\n"
  23.     } 
  24.     public function lookClassName() { 
  25.         echo __CLASS__ . "\n"
  26.     } 
  27. $obj = new SubClass; 
  28. $obj->sub();// 调用子类方法 
  29. $obj->parent();// 调用父类的方法 
  30. $obj->test();// 调用trait里的方法 
  31. $obj->lookClassName();// 调用同名方法 

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

上边这段例子的结果很明显的发现,最终当前类(子类)的方法被调用了,也就是三个里边都有同名方法时,当前类的方法优先。

接下来,注释(删除)当前类的lookClassName()方法。

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

看上边截图,很明显了,当子类(当前类)没有同名方法,只有父类(基类)和trait中的方法同名时,trait中的方法优先。

结论:当前类(子类)、trait和父类(基类)中有同名方法时“子类高于trait高于父类”。子类的方法会覆盖trait中的方法,而trait的方法会覆盖父类的方法。

前边有提到,trait可以随意组合,随意引用,那么是不是可以同时引入多个trait呢?是。在一个类内,可以同时use多个trait。

三、类内同时引入多个trait

  1. // trait 
  2. trait traitTest { 
  3.     public function test() { 
  4.         echo "trait test...\n"
  5.     } 
  6.     public function lookClassName() { 
  7.         echo "trait here\n"
  8.         echo __CLASS__ . "\n"
  9.     } 
  10. trait traitTest2 { 
  11.     public function test2() { 
  12.         echo "trait2 test...\n"
  13.     } 
  14.     public function lookClassName() { 
  15.         echo "trait2 here\n"
  16.         echo __CLASS__ . "\n"
  17.     } 
  18. trait traitTest3 { 
  19.     public function test3() { 
  20.         echo "trait3 test...\n"
  21.     } 
  22.     public function lookClassName() { 
  23.         echo "trait3 here\n"
  24.         echo __CLASS__ . "\n"
  25.     } 
  26. // 父类 
  27. class ParentClass { 
  28.     public function parent() { 
  29.         echo "parent...\n"
  30.     } 
  31.     public function lookClassName() { 
  32.         echo __CLASS__ . "\n"
  33.     } 
  34. // 子类 
  35. class SubClass extends ParentClass { 
  36.     use traitTest; 
  37.     use traitTest2, traitTest3; 
  38.     public function sub() { 
  39.         echo "sub...\n"
  40.     } 
  41.     public function lookClassName() { 
  42.         echo __CLASS__ . "\n"
  43.     } 
  44. $obj = new SubClass; 
  45. $obj->sub();// 调用子类方法 
  46. $obj->parent();// 调用父类的方法 
  47. $obj->test();// 调用trait里的方法 
  48. $obj->test2();// 调用trait2里的方法 
  49. $obj->test3();// 调用trait3里的方法 
  50. $obj->lookClassName();// 调用同名方法 

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

当需要同时引入多个trait时,只要use trait1, trait2, trait3,在use后边跟多个trait名字即可,多个trait之间用逗号分隔。

当然,也可以分开写,每次use一个trait进来。

此时又有新的问题产生了,如果引入的多个trait都有同名的方法,那么又会是谁优先?谁又被覆盖呢?

四、引入多个trait有同名方法

代码:

  1. // trait 
  2. trait traitTest { 
  3.     public function test() { 
  4.         echo "trait test...\n"
  5.     } 
  6.     public function lookClassName() { 
  7.         echo "trait here\n"
  8.         echo __CLASS__ . "\n"
  9.     } 
  10. trait traitTest2 { 
  11.     public function test2() { 
  12.         echo "trait2 test...\n"
  13.     } 
  14.     public function lookClassName() { 
  15.         echo "trait2 here\n"
  16.         echo __CLASS__ . "\n"
  17.     } 
  18. trait traitTest3 { 
  19.     public function test3() { 
  20.         echo "trait3 test...\n"
  21.     } 
  22.     public function lookClassName() { 
  23.         echo "trait3 here\n"
  24.         echo __CLASS__ . "\n"
  25.     } 
  26. // 父类 
  27. class ParentClass { 
  28.     public function parent() { 
  29.         echo "parent...\n"
  30.     } 
  31.     public function lookClassName() { 
  32.         echo __CLASS__ . "\n"
  33.     } 
  34. // 子类 
  35. class SubClass extends ParentClass { 
  36.     use traitTest, traitTest2, traitTest3 { 
  37.         traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTest 
  38.         traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2 
  39.     } 
  40.     public function sub() { 
  41.         echo "sub...\n"
  42.     } 
  43.     // public function lookClassName() { 
  44.     //     echo __CLASS__ . "\n"; 
  45.     // } 
  46. $obj = new SubClass; 
  47. $obj->sub();// 调用子类方法 
  48. $obj->parent();// 调用父类的方法 
  49. $obj->test();// 调用trait里的方法 
  50. $obj->test2();// 调用trait2里的方法 
  51. $obj->test3();// 调用trait3里的方法 
  52. $obj->lookClassName();// 调用同名方法 

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

说明(上边的源码和结果是解冲突之后的):

当子类没有(注释或者删除)lookClassName()方法时,调用lookClassName方法,则会调用trait中的方法,因为三个trait中都有同名方法,此时就会发生致命错误(冲突)。

报下边(看截图)的语法错误

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

此时,就需要解冲突。

解冲突,就需要使用到insteadof关键字,含义是“代替”,就是用哪个代替哪个。

  1. use traitTest, traitTest2, traitTest3 { 
  2.        traitTest2::lookClassName insteadof traitTest;// traitTest2代替了traitTest 
  3.        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2 
  4.    } 

解引入多个trait多个重名方法冲突时,需要在引入时使用insteadof关键字,逐一说明哪个trait的方法代替了哪个trait的(看上边引入代码的注释)。

根据上边引入的代码,是traitTest2的lookClassName代替了traitTest的,然后traitTest3的代替了traitTest2的。

因此,最终输出结果时,调用lookClassName(),输出的就是traitTest3的内容(输出结果看上边最近的“代码和结果截图”)。

当然,也可以换个写法:

  1. use traitTest, traitTest2, traitTest3 { 
  2.        traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3 
  3.        traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2 
  4.    } 

这个写法呢,是traitTest2和traitTest3互相代替了,那么此时反而没有traitTest什么事了。这个时候,再调用lookClassName()方法,输出的就是traitTest的lookClassName()方法的内容。

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

如图,当traitTest2和traitTest3互相代替后,直接输出了traitTest的内容。

到这基本就该结束了,但,有个特殊情况需要考虑一下。

我们之所以会引入多个trait,说明这几个trait里都有想使用的方法,那么非常巧合,其中同名方法正好又都想使用,被代替的方法还能使用么?

五、当引入多个trait,同名方法解冲突后,同时使用所有冲突的同名方法

解决:我们需要使用到另一个关键字“as”,此关键字的功能,简单理解就是给方法取一个别名。

代码:

  1. // trait 
  2. trait traitTest { 
  3.     public function test() { 
  4.         echo "trait test...\n"
  5.     } 
  6.     public function lookClassName() { 
  7.         echo "trait here\n"
  8.         echo __CLASS__ . "\n"
  9.     } 
  10. trait traitTest2 { 
  11.     public function test2() { 
  12.         echo "trait2 test...\n"
  13.     } 
  14.     public function lookClassName() { 
  15.         echo "trait2 here\n"
  16.         echo __CLASS__ . "\n"
  17.     } 
  18. trait traitTest3 { 
  19.     public function test3() { 
  20.         echo "trait3 test...\n"
  21.     } 
  22.     public function lookClassName() { 
  23.         echo "trait3 here\n"
  24.         echo __CLASS__ . "\n"
  25.     } 
  26. // 父类 
  27. class ParentClass { 
  28.     public function parent() { 
  29.         echo "parent...\n"
  30.     } 
  31.     public function lookClassName() { 
  32.         echo __CLASS__ . "\n"
  33.     } 
  34. // 子类 
  35. class SubClass extends ParentClass { 
  36.     use traitTest, traitTest2, traitTest3 { 
  37.         traitTest2::lookClassName insteadof traitTest3;// traitTest2代替了traitTest3 
  38.         traitTest3::lookClassName insteadof traitTest2;// traitTest3代替了traitTest2 
  39.         traitTest2::lookClassName as lookClassName2;// traitTest2的lookClassName改别名lookClassName2 
  40.         traitTest3::lookClassName as lookClassName3;// traitTest3的lookClassName改别名lookClassName3 
  41.     } 
  42.     public function sub() { 
  43.         echo "sub...\n"
  44.     } 
  45.     // public function lookClassName() { 
  46.     //     echo __CLASS__ . "\n"; 
  47.     // } 
  48. $obj = new SubClass; 
  49. $obj->sub();// 调用子类方法 
  50. $obj->parent();// 调用父类的方法 
  51. $obj->test();// 调用trait里的方法 
  52. $obj->test2();// 调用trait2里的方法 
  53. $obj->test3();// 调用trait3里的方法 
  54. $obj->lookClassName();// 调用同名方法 
  55. $obj->lookClassName2();// 调用traitTest2更名后的同名方法 
  56. $obj->lookClassName3();// 调用traitTest3更名后的同名方法 

代码和结果截图:

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

根据上图,就可以看出,当trait2和trait3互相代替,然后同名方法另起别名后,三个trait的同名方法,不再冲突,并且可以分别调用各自原本同名的方法。

到此要说的东西基本都说完了。算是对PHP的trait的一个小小的总结,希望可以帮到需要的朋友。

Tags: trait同名方法 trait冲突处理

分享到: