当前位置:首页 > PHP教程 > php面向对象 > 列表

PHP使用traits实现代码复用的例子

发布:smiling 来源: PHP粉丝网  添加日期:2015-04-08 14:24:30 浏览: 评论:0 

PHP 5.4中的traits,是新引入的特性,用于实现代码重用的方法,下面我们就一起来看看PHP使用traits实现代码复用的例子,希望文章可以帮助到各位.

PHP5.4后新增traits实现代码复用机制,Trait和类相似,但不能被实例化,无需继承,只需要在类中使用关键词use引入即可,可引入多个Traits,用','隔开.

(1)Trait简单使用

  1. <?php 
  2. trait A { 
  3.     public $var1 = 'test1'
  4.     public function test1() { 
  5.         echo 'trait A::test1()'
  6.     } 
  7.  
  8. trait B { 
  9.     public $var2 = 'test2'
  10.     public function test2() { 
  11.         echo 'trait B::test2()'
  12.     } 
  13.  
  14. class C { 
  15.     use A,B; 
  16.  
  17. $c = new C(); 
  18. echo $c->var1; //test1 
  19. $c->test2(); //trait B::test2() 
  20. ?> 

(2)优先级问题

Trait会覆盖继承的方法,当前类会覆盖Trait方法.

  1. trait A { 
  2.     public $var1 = 'test'
  3.     public function test() { 
  4.         echo 'A::test()'
  5.     } 
  6.     public function test1() { 
  7.         echo 'A::test1()'
  8.     } 
  9.  
  10. class B { 
  11.     public function test() { 
  12.         echo 'B::test()'
  13.     } 
  14.     public function test1() { 
  15.         echo 'B::test1()'
  16.     } 
  17. class C extends B{ 
  18.     use A; 
  19.     public function test() { 
  20.         echo 'c::test()'
  21.     } //开源软件:phpfensi.com 
  22.  
  23. $c = new C(); 
  24. $c->test(); //c::test() 
  25. $c->test1(); //A::test1() 

(3)多个Trait冲突问题

如果没有解决冲突,会产生致命错误,可用insteadof来明确使用冲突中哪一个方法,可用as操作符将其中一个冲突方法另起名.

  1. trait A { 
  2.     public function test() { 
  3.         echo 'A::test()'
  4.     } 
  5.  
  6. trait B { 
  7.     public function test() { 
  8.         echo 'B::test()'
  9.     } 
  10.  
  11. class C { 
  12.     use A,B { 
  13.         B::test insteadof A; 
  14.         B::test as t; 
  15.     } 
  16.  
  17. $c = new C(); 
  18. $c->test(); //B::test() 
  19. $c->t(); //B::test()   可以用as另起名 

(4)as可用来修改方法访问控制

  1. trait  HelloWorld  { 
  2.     public function  sayHello () { 
  3.         echo  'Hello World!' ; 
  4.     } 
  5.  
  6. // 修改 sayHello 的访问控制 
  7. class  A  { 
  8.     use  HelloWorld  {  sayHello  as protected; } 
  9.  
  10. // 给方法一个改变了访问控制的别名 
  11. // 原版 sayHello 的访问控制则没有发生变化 
  12. class  B  { 
  13.     use  HelloWorld  {  sayHello  as private  myPrivateHello ; } 
  14.  
  15. $b = new A(); 
  16. $b->sayHello(); //Fatal error: Call to protected method A::sayHello() from context '' 

(5)Trait中使用Trait

  1. trait A { 
  2.     public function test1() { 
  3.         echo 'test1'
  4.     } 
  5.  
  6. trait B { 
  7.     public function test2() { 
  8.         echo 'test2'
  9.     } 
  10.  
  11. trait C { 
  12.     use A,B; 
  13.  
  14. class D { 
  15.     use C; 
  16.  
  17. $d = new D(); 
  18. $d->test2();  //test2 

(6)Trait支持抽象方法、支持静态方法、不可以直接定义静态变量,但静态变量可被trait方法引用.

  1. trait A { 
  2.     public function test1() { 
  3.         static $a = 0; 
  4.         $a++; 
  5.         echo $a
  6.     } 
  7.  
  8.     abstract public function test2(); //可定义抽象方法 
  9.  
  10. class B { 
  11.     use A; 
  12.     public function test2() { 
  13.  
  14.     } 
  15.  
  16. $b = new B(); 
  17. $b->test1(); //1 
  18. $b->test1(); //2 

(7)Trait可定义属性,但类中不能定义同样名称属性.

  1. trait A { 
  2.    public $test1
  3.  
  4. class B { 
  5.     use A; 
  6.     public $test2

接着看.

  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(); 
  23. //输出结果如下: 
  24. study 
  25. eat 
  26. 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(); 
  27. //输出结果如下: 
  28. hello student 
  29. 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; 
  18. //输出结果如下: 
  19. 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(); 
  37. //输出结果如下: 
  38. Trait2::hello 
  39. Trait1::hi 
  40. Trait2::hello 
  41. Trait1::hi 
  42. Trait2::hi 
  43. 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方法被修改成私有的 
  22. ?> 

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(); 
  32. //输出结果如下: 
  33. Hello 
  34. World 
  35. get World 
  36. Doing something 
  37. ?>

Tags: PHP代码重复 traits代码复用

分享到: