7.9 Trait

trait 是PHP為類只能單繼承而實現的代碼復用機制。

trait 不能繼承,也不能實現接口。

trait 不能有常量。

trait 不能實例化。

trait 中可以使用 trait

trait 中可以使用抽象方法。

trait 中通過 insteadof 來解決命名沖突,也可以使用 as 來設置別名和訪問級別。

trait 中的優先級為 自己 > trait > 父類

trait 和類中如果有同名的屬性,那么需要保證他們的訪問級別和值相同才不會報錯。

一個簡單的 trait 例子

// trait
trait One{
    // 普通屬性
    public $name = 'One';

    // 不能有常量

    // 靜態屬性
    static $desc = 'Hello One';

    // 普通方法
    public function say(){
        echo $this->name . ': <br />';
        echo static::$desc . '<br />';
    }
}

// 類
class Foobar{
    // 引入 trait,可以引入多個,用逗號分開
    use One;
    // 構造函數
    public function __construct(){
        // 調用trait 中的函數
        $this->say();
    }
}

// 實例化
new Foobar();

當子類繼承了父類,同時引入了 trait,三者中如果有同名的成員(屬性、方法),那么優先級從大到小是 自己 > trait > 父類

// trait
trait One{
    public function fn(){
        echo "One::fn";
    }
}
// parent
class Two{
    public function fn(){
        echo "Two::fn";
    }
}
// class
class Foobar extends Two{
    use One;
    public function fn(){
        echo "Foobar::fn";
    }
}

// 實例化 輸出:Foobar::fn
(new Foobar())->fn();

當一個類使用了多個trait時,難免會發生 trait 之間會有命名沖突的問題,如果不解決,會報錯。

// trait
trait One{
    public function foo(){
        echo "One::foo <br />";
    }
    public function bar(){
        echo "One::bar <br />";
    }
}
trait Two{
    public function foo(){
        echo "Two::foo <br />";
    }
    public function bar(){
        echo "Two::bar <br />";
    }
}
trait Three{
    public function foo(){
        echo "Three::foo <br />";
    }
    public function bar(){
        echo "Three::bar <br />";
    }
}
// class
class Four{
    // 引入 trait
    use One, Two, Three {
        
        // 當 One 中的 foo方法 存在沖突時,排除掉 Two和Three 中的方法
        One::foo insteadof Two, Three;
        // 當 Two 中的 bar方法 存在沖突時,排除掉 One和Three 中的方法
        Two::bar insteadof One, Three;

        // 還一種方式是給方法起個別名
        Three::foo as tf;
    }
    public function call(){
        $this->foo();
        $this->bar();
        $this->tf();
    }
}

// 實例化
(new Four())->call();


/*

最終輸出

One::foo 
Two::bar 
Three::foo 

*/

當一個 trait 中的方法訪問級別較低時,可以通過 as 給它重新設置訪問級別

// trait
trait One{
    // 我是私有的,只能在類中使用,無法通過實例訪問
    private function say(){
        echo "private <br />";
    }
}

// 類
class Foobar{
    use One {
        // 調整方法的訪問控制級別
        say as public;
    }
}

// 實例化
(new Foobar())->say();

可以給 trait 添加抽象方法來強制要求使用者必須做一些事。

// trait
trait One{
    public function fn1(){
        return $this;
    }
    // 我是抽象方法
    public abstract function fn2();
}

// 類
class Foobar{
    use One;
    // 必須要實現抽象方法
    public function fn2(){
        echo "hello world";
    }
}

// 實例化
(new Foobar())->fn1()->fn2();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,896評論 1 10
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,767評論 18 399
  • PHP(一)基礎語法 本來就是學習筆記,就不說廢話了 參考 PHP 手冊陳惠貞 , 陳俊榮.PHP 7&MySQL...
    cndaqiang閱讀 1,109評論 1 1
  • 一過往生湖, 情入碧波庭, 再登云霄梯, 終見凌霄殿, 只為睹你一面, 情已不再,情已入微,終歸風輕云淡, 只剩嬌花。
    人如故閱讀 244評論 0 2
  • 當你成為大學老師,如果你不是博士,別人或者自己,環境就會告訴你,該考博了! 無論你愿不愿意,這是現實。 不得不說,...
    紅城浪子閱讀 369評論 2 1