參考php
引文php7
在php中,爲實現代碼複用,有了繼承,可是一個類只能繼承一個父類,不支持多繼承,接口支持多實現,可是接口又不太同樣,接口對外負責功能調用聲明,不負責實現,由實現了接口的類去實現具體功能邏輯,嚴格意義上來講,不算代碼複用,從php5.4開始,php實現了另一種代碼複用的方法,就是下文即將要說的trait。oop
traitthis
trait是爲擴展相似php單繼承的一種代碼複用機制,解除單繼承語言的限制,使開發人員可以自由地在不一樣層次結構中組合複用method。trait自己不能實例化,它依託於class存在。傳統繼承是上下層面的關係,trait則爲水平層面的組合。spa
優先級.net
對於相同方法名的方法而言,當前類的方法覆蓋trait方法,trait中方法覆蓋繼承的父類方法3d
class Base { public function sayHello() { echo 'Hello '; } } trait SayWorld { public function sayHello() { parent::sayHello(); echo 'World!'; } public function sayPeter() { echo "\nhello trait peter\n"; } } class MyHelloWorld extends Base { use SayWorld; public function sayPeter() { echo "\nhello class peter\n"; } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayPeter();
輸出code
多個traitblog
在類中,能夠聲明多個trait,將多個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();
輸出
trait衝突
若是trait之間定義了同名的方法,類中又組合了有同名方法的trait,會出現命名衝突,這個時候能夠使用insteadof指明調用衝突方法中的某一個。trait中能夠用as操做符爲某個方法引入別名,注意引入別名並不會對原方法重命名,別名不能和已包含的trait中方法名重複
trait A { public function smallTalk() { echo 'a'; } public function bigTalk() { echo 'A'; } public function helloPeter() { echo "hello peter\n"; } } trait B { public function smallTalk() { echo 'b'; } public function bigTalk() { echo 'B'; } public function helloAlice() { echo "hello alice\n"; } } class Talker { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; } } class TalkerAs { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; B::bigTalk as talk; } } class TalkerHello { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; // A::helloPeter as helloAlice; 別名不容許和已包含trait中方法重名 } } $talker = new Talker(); $talker->smallTalk(); $talker->bigTalk(); echo "\n"; $talkerAs = new TalkerAs(); $talkerAs->smallTalk(); $talkerAs->bigTalk(); $talkerAs->talk();
輸出
trait組合trait
正如class能夠使用多個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();
輸出
抽象成員方法
在trait中能夠定義抽象方法,類中若是要使用trait,必需要實現trait中的抽象方法
trait Hello { public function sayHelloWorld() { echo 'Hello ' . $this->getWorld() . "\n"; } abstract public function getWorld(); } class MyHelloWorld { private $world; use Hello; public function getWorld() { return $this->world; } public function setWorld($val) { $this->world = $val; } } $o = new MyHelloWorld(); $o->sayHelloWorld(); $o->setWorld('world'); $o->sayHelloWorld();
輸出
屬性
trait中也能夠定義屬性,但要注意trait定了某個屬性後,使用該trait的類中就不能定義一樣名稱的屬性,不然會產生fatal error。(屬性若是是兼容的(一樣的訪問控制符和默認值),就不會產生fatal error,但在php7以前,會有E_STRICT提醒)
trait PropertiesTrait { public $same = true; public $different = false; } class PropertiesExample { use PropertiesTrait; public $same = true; // PHP 7.0.0 後沒問題,以前版本是 E_STRICT 提醒 public $different = true; // 致命錯誤 }
php5.6
php7.1