在整理「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(); // validspa
$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的方法時,也能夠指定其訪問權限(public、protected、private);
咱們還可使用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,通往技術大牛的路上,咱們結伴同行!