PHP中實現代碼複用的Trait方法的一些特性

在整理「PHP基礎」這篇文檔時,看到了trait方法,感受比較陌生,因此今天上午用兩個小時的時間,查閱測試了trait方法的一些特性及用法,整理髮布了這篇博客。php

Trait PHP5.4 中的新特性,是 PHP 多重繼承的一種解決方案。例如,須要同時繼承兩個 Abstract Class 這將會是件很麻煩的事情,Trait 就是爲了解決這個問題。html


trait的簡單使用web

trait使用前須要先定義,trait的定義方式和類的定義方式差很少微信

trait first_trait {
    function first_method() { /* Code Here */ }
    function second_method() { /* Code Here */ }
oop

}學習

同時,若是要在 Class 中使用該 Trait,那麼須要使用 use 關鍵字測試

class first_class {
    //
注意這行,聲明使用 first_trait
    
use first_trait;
}
$obj = new first_class();// Executing the method from trait
$obj->first_method(); // valid
spa

$obj->second_method(); // valid.net

咱們在類中能夠直接聲明使用被定義好的trait,以後在類被實例化後,就可使用調用對象中方法的方式直接調用trait中的方法。無疑這增長了不少擴展性,由於類的繼承是單一的,而trait的使用卻不是單一的。設計


一個class中使用多個trait
在同一個 Class 中可使用多個 Trait,多個 Trait之間經過逗號分隔。

例如:

trait first_trait
{
    function first_method() { echo "method1"; }
}
trait second_trait {
    function second_method() { echo "method2"; }
}
class first_class {
    // now using more than one trait
    use first_trait, second_trait;
}
$obj= new first_class();
// Valid
$obj->first_method(); // Print : method1
// Valid

$obj->second_method(); // Print : method2


Trait 衝突

多個 Trait 之間同時使用不免會衝突,例如,若是兩個 trait 都插入了一個同名的方法,若是沒有明確解決衝突將會產生一個致命錯誤。

爲了解決多個 trait 在同一個類中的命名衝突,可使用關鍵字:insteadof 以及 as 
insteadof 
操做符用來明確指定使用哪個衝突方法;
as 
操做符用來給衝突的方法從新命名並引入。


trait first_trait {
    function 
first_function() { 
        echo "From First Trait";
    }
}
trait second_trait {
    //
這裏的名稱和 first_trait 同樣,會有衝突
    function 
first_function() { 
        echo "From Second Trait";
    }
}
class first_class {
    use first_trait, second_trait {
        //
在這裏聲明使用 first_trait first_function 替換
        // second_trait
中聲明的
        first_trait::first_function 
insteadof second_trait;

        second_trait::first_function as second_trait;

    }
}  


Trait 的抽象方法

咱們能夠在Trait 中聲明抽象方法,這樣,使用它的 Class 必須實現它。

trait first_trait {
    function first_method() { echo "method1"; }
    abstract public function second_method();//
這裏能夠加入修飾符,說明調用類必須實現它
}
class first_method {
    use first_trait;
    function second_method() {
        /* Code Here */
    }

}


Trait優先級

PHP手冊說法:優先順序是當前類的方法覆蓋了 trait 的方法,而 trait 覆蓋了被繼承的方法。

即優先級:當前類方法 > 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!


Trait訪問權限控制

與類類似的,咱們在定義trait的方法時,也能夠指定其訪問權限(publicprotectedprivate);

咱們還可使用as來修改方法的訪問權限。

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

與類類似,靜態成員分靜態方法和靜態屬性,兩者都是以static關鍵字來進行聲明的。

trait Counter {

    public function inc() {

        static $c = 0;

        $c = $c + 1;

        echo "$c\n";

    }

}

trait StaticExample {

    public static function doSomething() {

        return 'Doing something';

    }

}


Trait 屬性

在trait中定義了屬性後,類的實例能夠像訪問自身的屬性同樣訪問它。並且能夠給它設置訪問權限,就差不能實例化了……

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

trait PropertiesTrait {

    public $x = 1;

}

 

class PropertiesExample {

    use PropertiesTrait;

}

 

$example = new PropertiesExample;

$example->x;


須要特別注意的幾點

上面這些就是 Trait 基本的使用了,更詳細的能夠參k官方手冊。

這裏總結下注意的幾 點:

    - Trait 會覆蓋調用類繼承的父類方法

    - Trait 沒法如 Class 同樣使用 new 實例化

    - 單個 Trait 可由多個 Trait 組成

    - 在單個 Class 中,可使用多個 Trait

    - Trait 支持修飾詞(modifiers),例如 final、static、abstract

    - 咱們能使用 insteadof 以及 as 操做符解決 Trait 之間的衝突


參K文獻

    - http://php.net/manual/zh/language.oop5.traits.php

    - https://www.doubear.com/article/raityongfaxuexibiji.html

    - http://www.kuqin.com/web/20111119/315048.html

    - http://www.jb51.net/article/61260.htm


最後

歡迎關注個人我的微信「華偉君」,與我一塊兒學習探討PHP,通往技術大牛的路上,咱們結伴同行!

相關文章
相關標籤/搜索