当前位置:首页 > 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. class Person { 
  17.  
  18.     public function age() { 
  19.  
  20.         echo "i am 18 years old\n"
  21.  
  22.     } 
  23.  
  24.  
  25.    
  26.  
  27. class Student extends Person { 
  28.  
  29.     use Drive; 
  30.  
  31.     public function study() { 
  32.  
  33.         echo "Learn to drive \n"
  34.  
  35.     } 
  36.  
  37.  
  38.    
  39.  
  40. $student = new Student(); 
  41.  
  42. $student->study();  //输出:Learn to drive  
  43.  
  44. $student->age();    //输出:i am 18 years old 
  45.  
  46. $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. class Person { 
  23.  
  24.     public function hello() { 
  25.  
  26.         echo "hello 大家好\n"
  27.  
  28.     } 
  29.  
  30.     public function driving() { 
  31.  
  32.         echo "大家都会开车\n"
  33.  
  34.     } 
  35.  
  36.  
  37.    
  38.  
  39. class Student extends Person { 
  40.  
  41.     use Drive;//trait 的方法覆盖了基类Person中的方法,所以Person中的hello 和driving被覆盖 
  42.  
  43.     public function hello() { 
  44.  
  45.         echo "hello 新学员\n";//当方法或属性同名时,当前类中的方法会覆盖 trait的 方法,所以此处hello会覆盖trait中的 
  46.  
  47.         hello 
  48.  
  49.     } 
  50.  
  51.  
  52. $student = new Student(); 
  53.  
  54. $student->hello();    //输出:hello 新学员 
  55.  
  56. $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. trait Trait2 { 
  21.  
  22.     public function hello() { 
  23.  
  24.         echo "Trait2::hello\n"
  25.  
  26.     } 
  27.  
  28.     public function hi() { 
  29.  
  30.         echo "Trait2::hi\n"
  31.  
  32.     } 
  33.  
  34.  
  35.    
  36.  
  37. class Class1 {  
  38.  
  39.     use Trait1, Trait2; 
  40.  
  41.  
  42.    
  43.  
  44. //输出:Fatal error:  Trait method hello has not been applied, because there are collisions with other trait 
  45.  
  46.  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. trait Trait2 { 
  19.  
  20.     public function hello() { 
  21.  
  22.         echo "Trait2::hello\n"
  23.  
  24.     } 
  25.  
  26.     public function hi() { 
  27.  
  28.         echo "Trait2::hi\n"
  29.  
  30.     } 
  31.  
  32.  
  33. class Class1 { 
  34.  
  35.     use Trait1, Trait2 { 
  36.  
  37.         Trait2::hello insteadof Trait1; 
  38.  
  39.         Trait1::hi insteadof Trait2; 
  40.  
  41.     } 
  42.  
  43.  
  44.    
  45.  
  46. class Class2 { 
  47.  
  48.     use Trait1, Trait2 { 
  49.  
  50.         Trait2::hello insteadof Trait1; 
  51.  
  52.         Trait1::hi insteadof Trait2; 
  53.  
  54.         Trait2::hi as hei; 
  55.  
  56.         Trait1::hello as hehe; 
  57.  
  58.     } 
  59.  
  60.  
  61.    
  62.  
  63. $Obj1 = new Class1(); 
  64.  
  65. $Obj1->hello(); 
  66.  
  67. $Obj1->hi(); 
  68.  
  69. echo "\n"
  70.  
  71. $Obj2 = new Class2(); 
  72.  
  73. $Obj2->hello(); 
  74.  
  75. $Obj2->hi(); 
  76.  
  77. $Obj2->hei(); 
  78.  
  79. $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. class Class1 { 
  25.  
  26.     use Hello { 
  27.  
  28.         hello as protected
  29.  
  30.     } 
  31.  
  32.  
  33. class Class2 { 
  34.  
  35.     use Hello { 
  36.  
  37.         Hello::hello as private hi; 
  38.  
  39.     } 
  40.  
  41.  
  42. $Obj1 = new Class1(); 
  43.  
  44. $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的 
  45.  
  46.    
  47.  
  48. $Obj2 = new Class2(); 
  49.  
  50. $Obj2->hello(); # 输出: hello,我是周伯通,因为原来的hello方法仍然是公共的 
  51.  
  52. $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. trait World { 
  15.  
  16.     use Hello; 
  17.  
  18.     public function sayWorld() { 
  19.  
  20.         echo "hello world\n"
  21.  
  22.     } 
  23.  
  24.     abstract public function getWorld(); 
  25.  
  26.     public function inc() { 
  27.  
  28.         static $c = 0; 
  29.  
  30.         $c = $c + 1; 
  31.  
  32.         echo "$c\n"
  33.  
  34.     } 
  35.  
  36.     public static function doSomething() { 
  37.  
  38.         echo "Doing something\n"
  39.  
  40.     } 
  41.  
  42.  
  43.    
  44.  
  45. class HelloWorld { 
  46.  
  47.     use World; 
  48.  
  49.     public function getWorld() { 
  50.  
  51.         return 'do you get World ?'
  52.  
  53.     } 
  54.  
  55.  
  56.    
  57.  
  58. $Obj = new HelloWorld(); 
  59.  
  60. $Obj->sayHello(); 
  61.  
  62. $Obj->sayWorld(); 
  63.  
  64. echo $Obj->getWorld() . "\n"
  65.  
  66. HelloWorld::doSomething(); 
  67.  
  68. $Obj->inc(); 
  69.  
  70. $Obj->inc(); 

输出:

Hello 我是周伯通

hello world

do you get World ?

Doing something12

Tags: Trait

分享到: