php類和對象——Traits

來源:互聯網
上載者:User
自 PHP 5.4.0 起,PHP 實現了代碼複用的一個方法,稱為 traits。

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

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

Example #1 Trait 樣本

trait ezcReflectionReturnInfo{    function getReturnType(){}    function getReturnDescription(){}}class ezcReflectionMethod extends ReflectionMethod{    use ezcReflectionReturnInfo;}class ezcReflectionFunction extends ReflectionFunction{    use ezcReflectionReturnInfo;}

優先順序

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

Example #2 優先順序樣本

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

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!

Example #3 另一個優先順序順序的例子

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,可以都插入到一個類中。

Example #4 多個 trait 的用法

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 操作符可以將其中一個衝突的方法以另一個名稱來引入。

Example #5 衝突的解決

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

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

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;    }}$t = new Talker;$t->smallTalk(); //b$t->bigTalk(); //A$at = new Aliased_Talker;$at->smallTalk(); //b$at->bigTalk(); //A$at->talk(); //B

修改方法的存取控制

使用 as 文法還可以用來調整方法的存取控制。

Example #6 修改方法的存取控制

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 中的部分或全部成員。

Example #7 從 trait 來組成 trait

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 支援抽象方法的使用。

Example #8 表示通過抽象方法來進行強制要求

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 的靜態成員

靜態變數可以被 trait 的方法引用,但不能被 trait 定義。但是 trait 能夠為使用的類定義靜態方法。

Example #9 靜態變數

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

Example #10 靜態方法

trait StaticExample{    public static function doSomething(){        return 'Doing something.';    }}class Example{    use StaticExample;}Example::doSomething();

輸出結果:Doing something.

屬性

Trait 同樣可以定義屬性。

Example #11 定義屬性

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

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

Example #12 衝突

trait PropertiesTrait{    public $sname = true;    public $different = false;}class PropertiesExample{    use PropertiesTrait;    public $sname = true; //Strict Standards    public $different = true; //致命錯誤}
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.