国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > PHP > 正文

PHP使用traits實現代碼復用的例子

2024-09-04 11:43:47
字體:
來源:轉載
供稿:網友

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.     } //開源軟件:Vevb.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. ?>

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平陆县| 石河子市| 深圳市| 壶关县| 长葛市| 当涂县| 商河县| 闸北区| 开封市| 保康县| 香河县| 陆丰市| 丰都县| 贵南县| 庆安县| 洪湖市| 商河县| 菏泽市| 益阳市| 玉山县| 镶黄旗| 井陉县| 贵州省| 绍兴县| 金塔县| 浦县| 朝阳市| 营口市| 林周县| 临城县| 乌拉特后旗| 格尔木市| 德阳市| 赞皇县| 滦平县| 崇信县| 长顺县| 吉水县| 永春县| 平定县| 彭泽县|