類(lèi)中的某些成員如何才能被其他類(lèi)使用呢?使用繼承的話,這繼承鏈也太長(zhǎng)了,php提供了代碼復(fù)用技術(shù)trait。
1.定義:Trait
是為類(lèi)似 PHP 的單繼承語(yǔ)言
而準(zhǔn)備的一種代碼復(fù)用機(jī)制。trait可以使得單繼承語(yǔ)言
拜托為了復(fù)用而不得不繼承的尷尬,讓面向?qū)ο?/code>變得更加純粹。
2.基礎(chǔ)語(yǔ)法:
trait是一種類(lèi)似class
的關(guān)鍵字。
<?php trait Eat{ public $a=10; //trait內(nèi)允許有類(lèi)的成員屬性(包括靜態(tài)屬性),成員方法(包括靜態(tài)方法) public static $b=666; //const c=3.14; //trait內(nèi)不允許有常量 protected $e; //允許定義,但是實(shí)際不用 private $f; public function getA() { echo $this->a,"<br>"; } public static function getB() { echo self::$b,"<br>"; } } ?>
trait
是用來(lái)實(shí)現(xiàn)代碼的復(fù)用的,不可以被實(shí)例化也不可以被繼承(不是類(lèi))。
<?php trait Eat{} // $a=new Eat;//報(bào)錯(cuò) //calss A extends Eat{}//報(bào)錯(cuò) ?>
3.trait的使用
trait只是一段代碼的集合,使用時(shí)必須要使用use
進(jìn)行引用。
<?php trait Eat{ public $a=10; public static $b=666; //const c=3.14; public function getA() { echo $this->a,"<br>"; } public static function getB() { echo self::$b,"<br>"; } } class A{ use Eat; public function getC() { echo $this->a,"<br>"; } } $boy=new A(); $boy->getC(); $boy->getA(); $boy->getB(); ?>
一個(gè)類(lèi)可以使用多個(gè)trait。
<?php trait A1{ } trait A2{ } class People{ use A1,A2; } ?>
4.trait使用的問(wèn)題
a.如果同時(shí)引入的多個(gè)trait中有同名屬性,那么會(huì)產(chǎn)生沖突。
<?php trait A1{ public $a=11; } trait A2{ public $a=22; } class A3{ use A1,A2;//不允許同名屬性 public function geta(){ echo $this->a; } } $example=new A3(); ?>
b.如果同時(shí)引入的多個(gè)trait中有同名方法,那么會(huì)產(chǎn)生沖突,有兩種方案解決如A3、A4。
<?php trait A1{ public $a=11; public function eat(){ echo "A1中eat()方法","<br>"; } } trait A2{ public $b=22; public function eat(){ echo "A2中eat()方法","<br>"; } } class A3{ use A1,A2{ A1::eat insteadOf A2; //A1中的eat替代A2中的eat } } class A4{ use A1,A2{ A1::eat insteadOf A2;//A1中的eat替代A2中的eat A2::eat as eat2; //A2中的eat取別名eat2 } } $example=new A3(); $example->eat(); $example=new A4(); $example->eat2(); ?>
c.同名覆蓋問(wèn)題:如果類(lèi)中有與引入的trait同名成員,會(huì)有不同處理:
-
屬性:不允許重名,即類(lèi)中不允許定義與trait中同名的成員屬性(靜態(tài)屬性也一樣)。
-
方法:類(lèi)覆蓋trait。
d.繼承覆蓋問(wèn)題:如果類(lèi)中在使用trait
的同時(shí),也是繼承自父類(lèi),而trait中與父類(lèi)中有同名方法,那么trait
中將覆蓋父類(lèi)同名方法;如果要訪問(wèn)父類(lèi)方法,可以在trait同名方法中使用parent
關(guān)鍵字訪問(wèn)父類(lèi)同名方法。
<?php trait Eat{ public function eat(){ echo 'Eat::eat'; } } class Human{ public function eat(){ echo 'Human::eat'; } } //子類(lèi)繼承父類(lèi)同時(shí)使用trait class Man extends Human{ use Eat; } $m = new Man(); $m->eat(); ?>
e.trait自己不能訪問(wèn),只是用來(lái)給其他類(lèi)提供代碼復(fù)用的,因此允許類(lèi)在使用trait時(shí)更高里面方法的訪問(wèn)控制權(quán):在as
之后,使用目標(biāo)訪問(wèn)修飾限定符。
<?php trait Eat{ private function show(){ echo 'eat'; } } class Human{ use Eat{ show as public eshow; //注意:as是用來(lái)設(shè)定別名的,雖然沒(méi)有同名show,但是系統(tǒng)認(rèn)為show已經(jīng)存在,所以必須別名,權(quán)限的更改的方法不是 //本尊 } } $h = new Human(); $h->eshow(); //eat ?>
f.trait中可以使用抽象方法
,用來(lái)規(guī)范使用類(lèi)必須實(shí)現(xiàn)對(duì)應(yīng)抽象方法
:使用類(lèi)要么為抽象類(lèi),要么就必須實(shí)現(xiàn)抽象方法。
<?php trait Eat{ public function eat(); //抽象方法 } abstract class Human{ use Eat; //抽象類(lèi):可以不實(shí)現(xiàn)抽象方法 } class Animal{ use Eat; public function eat(){ //具體類(lèi):實(shí)現(xiàn)抽象方法 echo 'Animal::eat'; } } ?>
推薦:php教程,php視頻教程