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

PHP中Trait的用法及示例

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-31 11:00:36 浏览: 评论:0 

PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法,为了解决这个问题,php出了Trait这个特性。(Traits和Go语言的组合功能有点类似)。

用法:通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。

  1. <?php 
  2.  
  3. trait Drive { 
  4.  
  5.     public $carName = 'BMW'; 
  6.  
  7.     public function driving() { 
  8.  
  9.         echo "driving {$this->carName}\n"; 
  10.  
  11.     } 
  12.  
  13. } 
  14.  
  15.    
  16.  
  17. class Person { 
  18.  
  19.     public function age() { 
  20.  
  21.         echo "i am 18 years old\n"; 
  22.  
  23.     } 
  24.  
  25. } 
  26.  
  27.    
  28.  
  29. class Student extends Person { 
  30.  
  31.     use Drive; 
  32.  
  33.     public function study() { 
  34.  
  35.         echo "Learn to drive \n"; 
  36.  
  37.     } 
  38.  
  39. } 
  40.  
  41.    
  42.  
  43. $student = new Student(); 
  44.  
  45. $student->study();  //输出:Learn to drive  
  46.  
  47. $student->age();    //输出:i am 18 years old 
  48.  
  49. $student->driving();//输出:driving BMW 

结论:

Student类通过继承Person,有了age方法

通过组合Drive,有了driving方法和属性carName。

如果Trait、基类和本类中都存在某个同名的属性或者方法,最终会保留哪一个呢?通过下面的代码测试一下:

  1. <?php 
  2.  
  3.    
  4.  
  5. trait Drive { 
  6.  
  7.     public function hello() { 
  8.  
  9.         echo "hello 周伯通\n"; 
  10.  
  11.     } 
  12.  
  13.     public function driving() { 
  14.  
  15.         echo "周伯通不会开车\n"; 
  16.  
  17.     } 
  18.  
  19. } 
  20.  
  21.    
  22.  
  23. class Person { 
  24.  
  25.     public function hello() { 
  26.  
  27.         echo "hello 大家好\n"; 
  28.  
  29.     } 
  30.  
  31.     public function driving() { 
  32.  
  33.         echo "大家都会开车\n"; 
  34.  
  35.     } 
  36.  
  37. } 
  38.  
  39.    
  40.  
  41. class Student extends Person { 
  42.  
  43.     use Drive;//trait 的方法覆盖了基类Person中的方法,所以Person中的hello 和driving被覆盖 
  44.  
  45.     public function hello() { 
  46.  
  47.         echo "hello 新学员\n";//当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,所以此处hello会覆盖trait中的 
  48.  
  49.         hello 
  50.  
  51.     } 
  52.  
  53. } 
  54.  
  55. $student = new Student(); 
  56.  
  57. $student->hello();    //输出:hello 新学员 
  58.  
  59. $student->driving();  //输出:周伯通不会开车 

结论:当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,而 trait 的方法又覆盖了基类中的方法。

如果要组合多个Trait,通过逗号分隔 Trait名称:

use Trait1, Trait2;

如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误。

  1. <?php 
  2.  
  3. trait Trait1 { 
  4.  
  5.     public function hello() { 
  6.  
  7.         echo "Trait1::hello\n"; 
  8.  
  9.     } 
  10.  
  11.     public function hi() { 
  12.  
  13.         echo "Trait1::hi\n"; 
  14.  
  15.     } 
  16.  
  17. } 
  18.  
  19.    
  20.  
  21. trait Trait2 { 
  22.  
  23.     public function hello() { 
  24.  
  25.         echo "Trait2::hello\n"; 
  26.  
  27.     } 
  28.  
  29.     public function hi() { 
  30.  
  31.         echo "Trait2::hi\n"; 
  32.  
  33.     } 
  34.  
  35. } 
  36.  
  37.    
  38.  
  39. class Class1 {  
  40.  
  41.     use Trait1, Trait2; 
  42.  
  43. } 
  44.  
  45.    
  46.  
  47. //输出:Fatal error:  Trait method hello has not been applied, because there are collisions with other trait 
  48.  
  49.  methods on Class1 in 

使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码:

  1. <?php 
  2.  
  3. trait Trait1 { 
  4.  
  5.     public function hello() { 
  6.  
  7.         echo "Trait1::hello \n"; 
  8.  
  9.     } 
  10.  
  11.     public function hi() { 
  12.  
  13.         echo "Trait1::hi \n"; 
  14.  
  15.     } 
  16.  
  17. } 
  18.  
  19. trait Trait2 { 
  20.  
  21.     public function hello() { 
  22.  
  23.         echo "Trait2::hello\n"; 
  24.  
  25.     } 
  26.  
  27.     public function hi() { 
  28.  
  29.         echo "Trait2::hi\n"; 
  30.  
  31.     } 
  32.  
  33. } 
  34.  
  35. class Class1 { 
  36.  
  37.     use Trait1, Trait2 { 
  38.  
  39.         Trait2::hello insteadof Trait1; 
  40.  
  41.         Trait1::hi insteadof Trait2; 
  42.  
  43.     } 
  44.  
  45. } 
  46.  
  47.    
  48.  
  49. class Class2 { 
  50.  
  51.     use Trait1, Trait2 { 
  52.  
  53.         Trait2::hello insteadof Trait1; 
  54.  
  55.         Trait1::hi insteadof Trait2; 
  56.  
  57.         Trait2::hi as hei; 
  58.  
  59.         Trait1::hello as hehe; 
  60.  
  61.     } 
  62.  
  63. } 
  64.  
  65.    
  66.  
  67. $Obj1 = new Class1(); 
  68.  
  69. $Obj1->hello(); 
  70.  
  71. $Obj1->hi(); 
  72.  
  73. echo "\n"; 
  74.  
  75. $Obj2 = new Class2(); 
  76.  
  77. $Obj2->hello(); 
  78.  
  79. $Obj2->hi(); 
  80.  
  81. $Obj2->hei(); 
  82.  
  83. $Obj2->hehe(); 

输出:

  1. Trait2::hello 
  2.  
  3. Trait1::hi  
  4.  
  5. Trait2::hello 
  6.  
  7. Trait1::hi  
  8.  
  9. Trait2::hi 
  10.  
  11. Trait1::hello 
  12.  
  13. <?php 
  14.  
  15. trait Hello { 
  16.  
  17.     public function hello() { 
  18.  
  19.         echo "hello,我是周伯通\n"; 
  20.  
  21.     } 
  22.  
  23. } 
  24.  
  25. class Class1 { 
  26.  
  27.     use Hello { 
  28.  
  29.         hello as protected; 
  30.  
  31.     } 
  32.  
  33. } 
  34.  
  35. class Class2 { 
  36.  
  37.     use Hello { 
  38.  
  39.         Hello::hello as private hi; 
  40.  
  41.     } 
  42.  
  43. } 
  44.  
  45. $Obj1 = new Class1(); 
  46.  
  47. $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的 
  48.  
  49.    
  50.  
  51. $Obj2 = new Class2(); 
  52.  
  53. $Obj2->hello(); # 输出: hello,我是周伯通,因为原来的hello方法仍然是公共的 
  54.  
  55. $Obj2->hi();  # 报致命错误,因为别名hi方法被修改成私有的 

Uncaught Error: Call to protected method Class1::hello() from context '' in D:\web\mytest\p.php:18

Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:

  1. <?php 
  2.  
  3. trait Hello { 
  4.  
  5.     public function sayHello() { 
  6.  
  7.         echo "Hello 我是周伯通\n"; 
  8.  
  9.     } 
  10.  
  11. } 
  12.  
  13.    
  14.  
  15. trait World { 
  16.  
  17.     use Hello; 
  18.  
  19.     public function sayWorld() { 
  20.  
  21.         echo "hello world\n"; 
  22.  
  23.     } 
  24.  
  25.     abstract public function getWorld(); 
  26.  
  27.     public function inc() { 
  28.  
  29.         static $c = 0; 
  30.  
  31.         $c = $c + 1; 
  32.  
  33.         echo "$c\n"; 
  34.  
  35.     } 
  36.  
  37.     public static function doSomething() { 
  38.  
  39.         echo "Doing something\n"; 
  40.  
  41.     } 
  42.  
  43. } 
  44.  
  45.    
  46.  
  47. class HelloWorld { 
  48.  
  49.     use World; 
  50.  
  51.     public function getWorld() { 
  52.  
  53.         return 'do you get World ?'; 
  54.  
  55.     } 
  56.  
  57. } 
  58.  
  59.    
  60.  
  61. $Obj = new HelloWorld(); 
  62.  
  63. $Obj->sayHello(); 
  64.  
  65. $Obj->sayWorld(); 
  66.  
  67. echo $Obj->getWorld() . "\n"; 
  68.  
  69. HelloWorld::doSomething(); 
  70.  
  71. $Obj->inc(); 
  72.  
  73. $Obj->inc(); 

输出:

Hello 我是周伯通

hello world

do you get World ?

Doing something12

Tags: Trait

分享到: