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

详解PHP中的Traits

发布:smiling 来源: PHP粉丝网  添加日期:2021-06-14 22:40:48 浏览: 评论:0 

本文介绍了PHP中的Traits,Traits是一种为类似PHP的单继承语言而准备的代码复用机制,需要的朋友可以参考下。

PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法。php的Traits和Go语言的组合功能类似,通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。具体用法请看下面的代码:

  1. <?php 
  2.   trait Drive { 
  3.     public $carName = 'trait'
  4.     public function driving() { 
  5.       echo "driving {$this->carName}\n"
  6.     } 
  7.   } 
  8.   class Person { 
  9.     public function eat() { 
  10.       echo "eat\n"
  11.     } 
  12.   } 
  13.   class Student extends Person { 
  14.     use Drive; 
  15.     public function study() { 
  16.       echo "study\n"
  17.     } 
  18.   } 
  19.   $student = new Student(); 
  20.   $student->study(); 
  21.   $student->eat(); 
  22.   $student->driving(); 

输出结果如下:

study

eat

driving trait

上面的例子中,Student类通过继承Person,有了eat方法,通过组合Drive,有了driving方法和属性carName。

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

  1. <?php  
  2.   trait Drive { 
  3.     public function hello() { 
  4.       echo "hello drive\n"
  5.     } 
  6.     public function driving() { 
  7.       echo "driving from drive\n"
  8.     } 
  9.   } 
  10.   class Person { 
  11.     public function hello() { 
  12.       echo "hello person\n"
  13.     } 
  14.     public function driving() { 
  15.       echo "driving from person\n"
  16.     } 
  17.   } 
  18.   class Student extends Person { 
  19.     use Drive; 
  20.     public function hello() { 
  21.       echo "hello student\n"
  22.     } 
  23.   } 
  24.   $student = new Student(); 
  25.   $student->hello(); 
  26.   $student->driving(); 

输出结果如下:

hello student

driving from drive

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

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

use Trait1, Trait2;

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

  1. <?php 
  2. trait Trait1 { 
  3.   public function hello() { 
  4.     echo "Trait1::hello\n"
  5.   } 
  6.   public function hi() { 
  7.     echo "Trait1::hi\n"
  8.   } 
  9. trait Trait2 { 
  10.   public function hello() { 
  11.     echo "Trait2::hello\n"
  12.   } 
  13.   public function hi() { 
  14.     echo "Trait2::hi\n"
  15.   } 
  16. class Class1 { 
  17.   use Trait1, Trait2; 

输出结果如下:

PHP Fatal error: Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in ~/php54/trait_3.php on line 20

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

  1. <?php 
  2. trait Trait1 { 
  3.   public function hello() { 
  4.     echo "Trait1::hello\n"
  5.   } 
  6.   public function hi() { 
  7.     echo "Trait1::hi\n"
  8.   } 
  9. trait Trait2 { 
  10.   public function hello() { 
  11.     echo "Trait2::hello\n"
  12.   } 
  13.   public function hi() { 
  14.     echo "Trait2::hi\n"
  15.   } 
  16. class Class1 { 
  17.   use Trait1, Trait2 { 
  18.     Trait2::hello insteadof Trait1; 
  19.     Trait1::hi insteadof Trait2; 
  20.   } 
  21. class Class2 { 
  22.   use Trait1, Trait2 { 
  23.     Trait2::hello insteadof Trait1; 
  24.     Trait1::hi insteadof Trait2; 
  25.     Trait2::hi as hei; 
  26.     Trait1::hello as hehe; 
  27.   } 
  28. $Obj1 = new Class1(); 
  29. $Obj1->hello(); 
  30. $Obj1->hi(); 
  31. echo "\n"
  32. $Obj2 = new Class2(); 
  33. $Obj2->hello(); 
  34. $Obj2->hi(); 
  35. $Obj2->hei(); 
  36. $Obj2->hehe(); 

输出结果如下:

  1. Trait2::hello 
  2. Trait1::hi 
  3.  
  4. Trait2::hello 
  5. Trait1::hi 
  6. Trait2::hi 
  7. Trait1::hello 

as关键词还有另外一个用途,那就是修改方法的访问控制:

  1. <?php 
  2.   trait Hello { 
  3.     public function hello() { 
  4.       echo "hello,trait\n"
  5.     } 
  6.   } 
  7.   class Class1 { 
  8.     use Hello { 
  9.       hello as protected
  10.     } 
  11.   } 
  12.   class Class2 { 
  13.     use Hello { 
  14.       Hello::hello as private hi; 
  15.     } 
  16.   } 
  17.   $Obj1 = new Class1(); 
  18.   $Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的 
  19.   $Obj2 = new Class2(); 
  20.   $Obj2->hello(); # 原来的hello方法仍然是公共的 
  21.   $Obj2->hi(); # 报致命错误,因为别名hi方法被修改成私有的 

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

  1. <?php 
  2. trait Hello { 
  3.   public function sayHello() { 
  4.     echo "Hello\n"
  5.   } 
  6. trait World { 
  7.   use Hello; 
  8.   public function sayWorld() { 
  9.     echo "World\n"
  10.   } 
  11.   abstract public function getWorld(); 
  12.   public function inc() { 
  13.     static $c = 0; 
  14.     $c = $c + 1; 
  15.     echo "$c\n"
  16.   } 
  17.   public static function doSomething() { 
  18.     echo "Doing something\n"
  19.   } 
  20. class HelloWorld { 
  21.   use World; 
  22.   public function getWorld() { 
  23.     return 'get World'
  24.   } 
  25. $Obj = new HelloWorld(); 
  26. $Obj->sayHello(); 
  27. $Obj->sayWorld(); 
  28. echo $Obj->getWorld() . "\n"
  29. HelloWorld::doSomething(); 
  30. $Obj->inc(); 
  31. $Obj->inc(); 

输出结果如下:

  1. Hello 
  2. World 
  3. get World 
  4. Doing something 

以上就是本文的全部内容,希望对大家的学习有所帮助。

Tags: Traits

分享到: