php--Trait 特性及作用

前言

眾所周知,一直以來(lái)PHP和很多語(yǔ)言一樣是單繼承的語(yǔ)言,但是常常在編碼過(guò)程中,我們需要在當(dāng)前類(lèi)中使用兩個(gè)或兩個(gè)以上的其他類(lèi)的方法,這種情況下繼承就不能實(shí)現(xiàn),而往往采用new方式實(shí)例化很多要用到的類(lèi),這樣就會(huì)很影響代碼的結(jié)構(gòu)和開(kāi)發(fā)規(guī)范。于是Trait類(lèi)誕生了,它是一種代碼復(fù)用的語(yǔ)法,能夠?qū)崿F(xiàn)一個(gè)類(lèi)中引用多個(gè)其他類(lèi)的方法。

一、概念

Traits 是一種為類(lèi)似 PHP 的單繼承語(yǔ)言而準(zhǔn)備的代碼復(fù)用機(jī)制。Trait 為了減少單繼承語(yǔ)言的限制,使開(kāi)發(fā)人員能夠自由地在不同層次結(jié)構(gòu)內(nèi)獨(dú)立的類(lèi)中復(fù)用方法集。Traits 和類(lèi)組合的語(yǔ)義是定義了一種方式來(lái)減少?gòu)?fù)雜性,避免傳統(tǒng)多繼承和混入類(lèi)(Mixin)相關(guān)的典型問(wèn)題。
Trait和Class相似,但僅僅旨在用細(xì)粒度和一致的方式來(lái)組合功能。無(wú)法通過(guò)trait自身來(lái)實(shí)例化。它為傳統(tǒng)繼承增加了水平特性的組合;也就是說(shuō),應(yīng)用的幾個(gè)Class之間不需要繼承。

二、Trait類(lèi)的使用

簡(jiǎn)單地講,Trait就是一種不同于繼承的語(yǔ)法,定義一個(gè)trait類(lèi),在其他類(lèi)中使用它則是采用use關(guān)鍵字,有點(diǎn)類(lèi)似于命名空間的用法,但是含義不同。use關(guān)鍵字在一個(gè)類(lèi)中引入Trait類(lèi)后,相當(dāng)于require或include了一段代碼進(jìn)來(lái),不同之處在于use的Trait類(lèi)與當(dāng)前類(lèi)是可以看做同一個(gè)類(lèi)的,即當(dāng)前類(lèi)可以用$this關(guān)鍵字調(diào)用Trait類(lèi)的方法。

image.png
三、Trait類(lèi)的訪問(wèn)控制

我們知道,繼承的方式,如果基類(lèi)是private修飾控制的,則子類(lèi)是無(wú)法調(diào)用的。但是Trait不一樣,因?yàn)樗?lèi)似于Require到當(dāng)前類(lèi)中了,所以不管是public、protected或private都是可以直接使用的。示例如下:

image.png
四、Trait類(lèi)的優(yōu)先級(jí)控制

Trait類(lèi)與當(dāng)前使用類(lèi)、繼承的基類(lèi)之間的調(diào)用優(yōu)先級(jí)順序如下:
當(dāng)前使用類(lèi)>Trait類(lèi)>繼承的基類(lèi)

當(dāng)存在同名方法時(shí),會(huì)根據(jù)優(yōu)先級(jí)覆蓋掉同名的類(lèi)。具體示例如下:

1、Trait類(lèi)覆蓋基類(lèi)

image.png

2、當(dāng)前類(lèi)覆蓋Trait類(lèi)

image.png
五、多個(gè)Trait類(lèi)的沖突控制

在PHP中,如果當(dāng)前類(lèi)use了兩個(gè)Trait類(lèi),同時(shí)兩個(gè)trait類(lèi)都存在一個(gè)同名的方法,此時(shí)如果沒(méi)有明確解決沖突將會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤。
對(duì)于這種情況,PHP官方給出了兩個(gè)解決方案:
1、insteadof關(guān)鍵字:通過(guò)該關(guān)鍵字指定方法名沖突時(shí)該使用哪個(gè)Trait類(lèi)的方法,即:
如果C類(lèi)use了A、B兩個(gè)Trait類(lèi),且A、B兩個(gè)類(lèi)都存在a、b方法,則在C類(lèi)use A、B類(lèi)時(shí)使用insteadof聲明沖突的解決方法即可:

use A, B {
  B::a insteadof A; //a方法沖突時(shí)使用B類(lèi)的a方法而不使用A類(lèi)的a方法
  A::b insteadof B; //b方法沖突時(shí)使用A類(lèi)的b方法而不使用B類(lèi)的b方法
}

2、as關(guān)鍵字:通過(guò)as關(guān)鍵字將同名方法指定為一個(gè)別名,且僅作用于當(dāng)前類(lèi)中。示例如下:

use A, B {
  B::a as c; //聲明B類(lèi)的a方法為c,作用于該類(lèi)
  A::b as d; //聲明A類(lèi)的b方法為d,作用于該類(lèi)
}
六、與繼承、直接實(shí)例化的區(qū)別

對(duì)于當(dāng)前一個(gè)類(lèi)需要用到另一個(gè)或多個(gè)類(lèi)的方法的情況,我們一般會(huì)想到的方式有繼承、直接實(shí)例化另外一個(gè)或多個(gè)類(lèi)等等的方法,下面來(lái)對(duì)比一下這些方法和Trait類(lèi)的區(qū)別:
1、繼承方式:對(duì)于繼承,可以完美地復(fù)用另一個(gè)類(lèi)的一些方法,但是對(duì)于需要復(fù)用多個(gè)類(lèi)的方法時(shí),PHP是不支持多繼承的,而且只能訪問(wèn)public和protected方法;
2、與直接實(shí)例化的區(qū)別:我們也可以在當(dāng)前類(lèi)中直接實(shí)例化要用到的A類(lèi)與B類(lèi),但是這種方法在控制訪問(wèn)范圍反面,只允許訪問(wèn)A、B類(lèi)中public的方法;
3、使用Trait類(lèi)則完全將A、B兩個(gè)類(lèi)的方法導(dǎo)入到當(dāng)前類(lèi)中,可以視為當(dāng)前類(lèi)的一部分,唯一區(qū)別是可能存在于當(dāng)前類(lèi)同名的方法,此時(shí)由優(yōu)先級(jí)順序來(lái)控制。

補(bǔ)充:PHP多繼承示例

class Base{
  public function sayHello(){
    echo "hello ";
  }
}
trait SayWorld{
  public function sayHello(){
    parent::sayHello();
    echo "world".PHP_EOL;
  }
}
trait SayWorld2{
  public function sayHello2(){
    echo "PHP".PHP_EOL;
  }
}
class MyHelloWorld extends Base{
  use SayWorld,SayWorld2;
}
$s = new MyHelloWorld();
$s->sayHello();
$s->sayHello2();

輸出結(jié)果:

hello  world
PHP

上面就是些 Trait 比較基本的使用了。這里總結(jié)下注意的幾點(diǎn):
1.Trait 會(huì)覆蓋調(diào)用類(lèi)繼承的父類(lèi)方法,但也會(huì)被當(dāng)前類(lèi)所覆蓋
2.Trait 無(wú)法如 Class 一樣使用 new 實(shí)例化
3.單個(gè) Trait 可由多個(gè) Trait 組成
4.在單個(gè) Class 中,可以使用多個(gè) Trait
5.Trait 支持修飾詞(modifiers),例如 final、static、abstract
6.我們能使用 insteadof 以及 as 操作符解決 Trait 之間的沖突
7.Trait中不區(qū)分修飾符,即可以操作Trait中的public protected private級(jí)別的屬性和方法,這個(gè)extends繼承有所不同

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容