站長資訊網
最全最豐富的資訊網站

PHP實現代碼復用的traits新特性的方法

PHP實現代碼復用的traits新特性的方法

在閱讀yii2源碼的時候接觸到了trait,就學習了一下,寫下博客記錄一下。

自 PHP 5.4.0 起,PHP 實現了代碼復用的一個方法,稱為 traits。

Traits 是一種為類似 PHP 的單繼承語言而準備的代碼復用機制。Trait 為了減少單繼承語言的限制,使開發人員能夠自由地在不同層次結構內獨立的類中復用方法集。Traits 和類組合的語義是定義了一種方式來減少復雜性,避免傳統多繼承和混入類(Mixin)相關的典型問題。

Trait 和一個類相似,但僅僅旨在用細粒度和一致的方式來組合功能。Trait 不能通過它自身來實例化。它為傳統繼承增加了水平特性的組合;也就是說,應用類的成員不需要繼承。

Trait 示例

代碼如下:

<?php trait ezcReflectionReturnInfo {     function getReturnType() { /*1*/ }     function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod {     use ezcReflectionReturnInfo;     /* ... */ } class ezcReflectionFunction extends ReflectionFunction {     use ezcReflectionReturnInfo;     /* ... */ } ?>

優先級

從基類繼承的成員被 trait 插入的成員所覆蓋。優先順序是來自當前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。

優先順序示例

代碼如下:

<?php class Base {     public function sayHello() {         echo 'Hello ';     } } trait SayWorld {     public function sayHello() {         parent::sayHello();         echo 'World!';     } } class MyHelloWorld extends Base {     use SayWorld; } $o = new MyHelloWorld(); $o->sayHello(); ?>

以上例程會輸出:Hello World!

從基類繼承的成員被插入的 SayWorld Trait 中的 sayHello 方法所覆蓋。其行為 MyHelloWorld 類中定義的方法一致。優先順序是當前類中的方法會覆蓋 trait 方法,而 trait 方法又覆蓋了基類中的方法。

另一個優先級順序的例子

代碼如下:

<?php trait HelloWorld {     public function sayHello() {         echo 'Hello World!';     } } class TheWorldIsNotEnough {     use HelloWorld;     public function sayHello() {         echo 'Hello Universe!';     } } $o = new TheWorldIsNotEnough(); $o->sayHello(); ?>

以上例程會輸出:Hello Universe!

多個 trait

通過逗號分隔,在 use 聲明列出多個 trait,可以都插入到一個類中。

多個 trait 的用法的例子

代碼如下:

<?php trait Hello {     public function sayHello() {         echo 'Hello ';     } } trait World {     public function sayWorld() {         echo 'World';     } } class MyHelloWorld {     use Hello, World;     public function sayExclamationMark() {         echo '!';     } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld(); $o->sayExclamationMark(); ?>

以上例程會輸出:Hello World!

沖突的解決

如果兩個 trait 都插入了一個同名的方法,如果沒有明確解決沖突將會產生一個致命錯誤。

為了解決多個 trait 在同一個類中的命名沖突,需要使用 insteadof 操作符來明確指定使用沖突方法中的哪一個。

以上方式僅允許排除掉其它方法,as 操作符可以將其中一個沖突的方法以另一個名稱來引入。

沖突解決的例子

代碼如下:

<?php trait A {     public function smallTalk() {         echo 'a';     }     public function bigTalk() {         echo 'A';     } } trait B {     public function smallTalk() {         echo 'b';     }     public function bigTalk() {         echo 'B';     } } class Talker {     use A, B {         B::smallTalk insteadof A;         A::bigTalk insteadof B;     } } class Aliased_Talker {     use A, B {         B::smallTalk insteadof A;         A::bigTalk insteadof B;         B::bigTalk as talk;     } } ?>

在本例中 Talker 使用了 trait A 和 B。由于 A 和 B 有沖突的方法,其定義了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk。

Aliased_Talker 使用了 as 操作符來定義了 talk 來作為 B 的 bigTalk 的別名。

修改方法的訪問控制

使用 as 語法還可以用來調整方法的訪問控制。

修改方法的訪問控制的例子

代碼如下:

<?php trait HelloWorld {     public function sayHello() {         echo 'Hello World!';     } } // 修改 sayHello 的訪問控制 class MyClass1 {     use HelloWorld { sayHello as protected; } } // 給方法一個改變了訪問控制的別名 // 原版 sayHello 的訪問控制則沒有發生變化 class MyClass2 {     use HelloWorld { sayHello as private myPrivateHello; } } ?>

從 trait 來組成 trait

正如類能夠使用 trait 一樣,其它 trait 也能夠使用 trait。在 trait 定義時通過使用一個或多個 trait,它能夠組合其它 trait 中的部分或全部成員。

從 trait 來組成 trait的例子

代碼如下:

<?php trait Hello {     public function sayHello() {         echo 'Hello ';     } } trait World {     public function sayWorld() {         echo 'World!';     } } trait HelloWorld {     use Hello, World; } class MyHelloWorld {     use HelloWorld; } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld(); ?>

以上例程會輸出:Hello World!

Trait 的抽象成員

為了對使用的類施加強制要求,trait 支持抽象方法的使用。

表示通過抽象方法來進行強制要求的例子

代碼如下:

<?php trait Hello {     public function sayHelloWorld() {         echo 'Hello'.$this->getWorld();     }     abstract public function getWorld(); } class MyHelloWorld {     private $world;     use Hello;     public function getWorld() {         return $this->world;     }     public function setWorld($val) {         $this->world = $val;     } } ?>

Trait 的靜態成員

Traits 可以被靜態成員靜態方法定義。

靜態變量的例子

代碼如下:

<?php trait Counter {     public function inc() {         static $c = 0;         $c = $c + 1;         echo "$cn";     } } class C1 {     use Counter; } class C2 {     use Counter; } $o = new C1(); $o->inc(); // echo 1 $p = new C2(); $p->inc(); // echo 1 ?>

靜態方法的例子

代碼如下:

<?php trait StaticExample {     public static function doSomething() {         return 'Doing something';     } } class Example {     use StaticExample; } Example::doSomething(); ?>

靜態變量和靜態方法的例子

代碼如下:

<?php trait Counter {     public static $c = 0;     public static function inc() {         self::$c = self::$c + 1;         echo self::$c . "n";     } } class C1 {     use Counter; } class C2 {     use Counter; } C1::inc(); // echo 1 C2::inc(); // echo 1 ?>

屬性
Trait 同樣可以定義屬性。

定義屬性的例子

代碼如下:

<?php trait PropertiesTrait {     public $x = 1; } class PropertiesExample {     use PropertiesTrait; } $example = new PropertiesExample; $example->x; ?>

如果 trait 定義了一個屬性,那類將不能定義同樣名稱的屬性,否則會產生一個錯誤。如果該屬性在類中的定義與在 trait 中的定義兼容(同樣的可見性和初始值)則錯誤的級別是 E_STRICT,否則是一個致命錯誤。

沖突的例子

代碼如下:

<?php trait PropertiesTrait {     public $same = true;     public $different = false; } class PropertiesExample {     use PropertiesTrait;     public $same = true; // Strict Standards     public $different = true; // 致命錯誤 } ?>

Use的不同

不同use的例子

代碼如下:

<?php namespace FooBar; use FooTest;  // means FooTest - the initial  is optional ?> <?php namespace FooBar; class SomeClass {     use FooTest;   // means FooBarFooTest } ?>

第一個use是用于 namespace 的 use FooTest,找到的是 FooTest,第二個 use 是使用一個trait,找到的是FooBarFooTest

__CLASS____TRAIT__
__CLASS__ 返回 use trait 的 class name,__TRAIT__返回 trait name

示例如下

代碼如下:

<?php trait TestTrait {     public function testMethod() {         echo "Class: " . __CLASS__ . PHP_EOL;         echo "Trait: " . __TRAIT__ . PHP_EOL;     } } class BaseClass {     use TestTrait; } class TestClass extends BaseClass { } $t = new TestClass(); $t->testMethod(); //Class: BaseClass //Trait: TestTrait

Trait單例

實例如下

代碼如下:

<?php trait singleton {         /**      * private construct, generally defined by using class      */     //private function __construct() {}     public static function getInstance() {         static $_instance = NULL;         $class = __CLASS__;         return $_instance ?: $_instance = new $class;     }     public function __clone() {         trigger_error('Cloning '.__CLASS__.' is not allowed.',E_USER_ERROR);     }     public function __wakeup() {         trigger_error('Unserializing '.__CLASS__.' is not allowed.',E_USER_ERROR);     } } /** * Example Usage */ class foo {     use singleton;     private function __construct() {         $this->name = 'foo';     } } class bar {     use singleton;     private function __construct() {         $this->name = 'bar';     } } $foo = foo::getInstance(); echo $foo->name; $bar = bar::getInstance(); echo $bar->name;

調用trait方法

雖然不很明顯,但是如果Trait的方法可以被定義為在普通類的靜態方法,就可以被調用

實例如下

代碼如下:

<?php  trait Foo {      function bar() {          return 'baz';      }  }  echo Foo::bar(),"\n";  ?>

相關學習推薦:PHP編程從入門到精通

贊(0)
分享到: 更多 (0)
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
国产69精品久久久久99| 国产成人精品AA毛片| 日韩精品无码一区二区三区| 精品精品国产理论在线观看| mm1313亚洲精品无码又大又粗| 精品午夜福利无人区乱码一区| 国产精品亚洲αv天堂无码| 97久久超碰成人精品网站| 精品一久久香蕉国产线看播放| 麻豆精品国产免费观看| 亚洲av永久无码精品秋霞电影影院| 亚洲国产日韩在线观频| 精品国产乱码一区二区三区| 久久久久成人精品无码| 日本精品视频一区二区三区| 无码国产精品一区二区免费模式 | 国产精品手机在线| 亚洲综合精品香蕉久久网| 国产成人精品无码专区| 91久久精品国产免费直播| 久久久久久久久久久免费精品| 国产精品哟哟视频| 久久精品国产亚洲av麻豆蜜芽 | 国产精品美女久久久网站动漫| 久久精品天天中文字幕人妻| 亚欧洲精品在线视频免费观看| 国产高清在线精品二区| 精品人妻无码区在线视频| 亚洲热线99精品视频| 亚洲国产精品日韩在线| 欧美黑人欧美精品刺激| 91精品一区二区| 久久久久久久国产精品电影| 国产精品美女久久久久av爽 | 色婷婷在线精品国自产拍| 国产呦小j女精品视频| 日韩伦理片电影在线免费观看| 成人综合婷婷国产精品久久蜜臀| 亚洲欧洲精品在线| 久久夜色精品国产亚洲AV动态图| 97久久精品国产精品青草|