博客列表 >trait的应用场景及其与接口、抽象类之间的区别

trait的应用场景及其与接口、抽象类之间的区别

longlong
longlong原创
2020年07月25日 19:30:38838浏览

1. trait的应用场景

1.1 实现代码的复用

  1. <?php
  2. // trait功能之一:实现代码的复用
  3. trait tSum
  4. {
  5. // 写一个公共的求和方法
  6. public function sum ($a,$b) {
  7. return $a+$b;
  8. }
  9. }
  10. class Sum1
  11. {
  12. use tSum;
  13. }
  14. class Sum2
  15. {
  16. use tSum;
  17. }
  18. echo (new Sum1)->sum(10,20);
  19. echo '<hr>';
  20. echo (new Sum2)->sum(10,20);

1.2 在继承上下文中的应用

  1. <?php
  2. // 在继承上下文中的应用,控制优先级,降低单继承的影响
  3. trait tMiddle
  4. {
  5. public static function show () {
  6. echo '访问到trait';
  7. }
  8. }
  9. // 基类/父类
  10. abstract class Big
  11. {
  12. public static function show () {
  13. echo '访问到基类';
  14. }
  15. }
  16. // 扩展类/子类
  17. class Small extends Big
  18. {
  19. use tMiddle;
  20. public static function show () {
  21. echo '访问到扩展类';
  22. }
  23. }
  24. // 实例化扩展类来访问,看看优先级(遇到同名方法时)
  25. // 1. 不引入trait时
  26. // Small::show();
  27. // 此时输出:访问到扩展类,表示扩展类>基类
  28. // 2.引入trait时,并注释掉扩展类中的方法
  29. // Small::show();
  30. // 此时输出:访问到trait,表示trait>基类
  31. // 3.引入trait,保留扩展类中的方法
  32. Small::show();
  33. // 此时输出:访问到扩展类,表示扩展类>trait和基类
  34. // 综合上述三种情况:当遇到同名方法时,且trait在子类中调用时,扩展类>trait>基类

1.3 trait实现功能的扩展

  1. <?php
  2. // trait功能之实现功能的扩展:组合运用多个trait
  3. // 求和的trait
  4. trait Sum
  5. {
  6. public static function sum (int $a, int $b) :int
  7. {
  8. return $a+$b;
  9. }
  10. }
  11. // 求差的trait
  12. trait Sub
  13. {
  14. public static function subtraction (int $a,int $b) :int
  15. {
  16. return $a-$b>=0 ? $a-$b :$b-$a;
  17. }
  18. }
  19. // 把求和与求差组合为一个trait
  20. trait Demo
  21. {
  22. use Sum,Sub;
  23. }
  24. // 求积的class
  25. class Multi
  26. {
  27. // 如果要在这个类中再加入求和与求差,只需引入Sum和Sub这两个trait
  28. use Sum,Sub;
  29. public static function multiplication (int $a,int $b) :int
  30. {
  31. return $a*$b;
  32. }
  33. }
  34. echo "两数之和是:".Multi::sum(10,20),'<hr>';
  35. echo "两数之差是:".Multi::subtraction(10,20),'<hr>';
  36. echo "两数相乘是:".Multi::multiplication(10,20),'<hr>';
  37. // 求商的class
  38. class Divi
  39. {
  40. // 如果把以上两个trait合并为一个,那么在这个类中只需引入一个trait即可实现求和与求差
  41. use Demo;
  42. public static function division (int $a,int $b) :float
  43. {
  44. return $a/$b;
  45. }
  46. }
  47. echo "两数之和是:".Divi::sum(20,20),'<hr>';
  48. echo "两数之差是:".Divi::subtraction(20,20),'<hr>';
  49. echo "两数相除是:".Divi::division(20,20),'<hr>';

1.4 命名冲突的解决

  1. <?php
  2. // trait的命名冲突解决办法
  3. trait tDemo1
  4. {
  5. public function show () {
  6. echo 'aaaaaa','<hr>';
  7. }
  8. }
  9. trait tDemo2
  10. {
  11. public function show () {
  12. echo 'bbbbbb','<hr>';
  13. }
  14. }
  15. trait tDemo3
  16. {
  17. public function show () {
  18. echo 'cccccc','<hr>';
  19. }
  20. }
  21. // 示例一:
  22. trait tDemo4
  23. {
  24. // 两个trait中的方法名一样,有冲突,会报错,解决方案如下:
  25. // 1. insteadof 操作符来明确指定使用冲突方法中的哪一个
  26. use tDemo1,tDemo2,tDemo3
  27. {
  28. // tDemo1::show insteadOf tDemo2,tDemo3;
  29. // tDemo2::show insteadOf tDemo3,tDemo1;
  30. tDemo3::show insteadOf tDemo1,tDemo2;
  31. }
  32. }
  33. class Work1
  34. {
  35. use tDemo4;
  36. }
  37. (new Work1)->show();
  38. // 示例二:
  39. trait tDemo5
  40. {
  41. use tDemo1,tDemo2
  42. {
  43. // 2. 使用 as 可以给trait中的方法取别名,但不是重命名,也不会影响其方法
  44. tDemo1::show insteadOf tDemo2;
  45. tDemo1::show as s1;
  46. tDemo2::show as s2;
  47. }
  48. }
  49. class Work2
  50. {
  51. use tDemo5;
  52. }
  53. (new Work2)->show();
  54. (new Work2)->s1();
  55. (new Work2)->s2();

  1. <?php
  2. // trait中as语法调整方法的访问控制
  3. trait tDemo
  4. {
  5. public static function show () {
  6. return __METHOD__;
  7. }
  8. }
  9. class Work1
  10. {
  11. use tDemo;
  12. }
  13. echo Work1::show(),'<hr>';
  14. class Work2
  15. {
  16. // 将访问控制修改为protected
  17. use tDemo{
  18. show as protected;
  19. }
  20. }
  21. // 修改访问控制为protected以后,外部将不能调用
  22. echo Work2::show();

1.5 trait与interface的组合

  1. <?php
  2. // trait与interface组合:可将实现类中的代码放入trait,然后再调用,让实现类的代码尽量简介、清晰
  3. // if (!interface_exists(iDemo)) :
  4. interface iDemo
  5. {
  6. public function show ();
  7. }
  8. // endif;
  9. // if (!trait_exists(tDemo)) :
  10. trait tDemo
  11. {
  12. public function show () {
  13. return 'aaa';
  14. }
  15. }
  16. // endif;
  17. // if (!class_exists(Demo)) :
  18. class Demo
  19. {
  20. use tDemo;
  21. }
  22. // endif;
  23. echo (new Demo)->show();

1.6 trait与接口和抽象类之间的区别

它们之间的区别我就不做实例演示,这里谈下我的理解。

  • 它们都有自己的应用场景,比如:trait用作代码复用,不仅可以把一些公共的方法放在其中,也可以把实现类的代码放在其中,方便调用;

  • 接口用于将设计与实现完全分离,在实际项目中。肯定是不可或缺的,需要把设计方法放在其中,之后再去实现这个接口

  • 抽象类,可以理解为一个中间层,用它去实现接口,并且使用抽象类实现接口的好处是可以不用实现接口的所有方法,还能把真正实现类的一些公共操作放在其中,也还能在抽象类中定义一些抽象方法,最终让子类去实现

2. 总结

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议