蕭峰與郭靖教你學(xué)會(huì)PHP的Trait

自PHP5.4之前,PHP面向?qū)ο笮枰獜?fù)用代碼的方式是使用類的繼承。但PHP只支持單繼承,在應(yīng)對(duì)較復(fù)雜的業(yè)務(wù)邏輯中,單繼承就顯得捉襟見肘了。

trait的使用場(chǎng)景

如以下應(yīng)用場(chǎng)景:

class Person {
    public function eat() {
        echo "我是人,我能吃飯<br />";
    }
}

class GuoJing extends Person {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

class XiaoFeng extends Person {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}
蕭峰

Guojing 類 與 XiaoFeng 類都繼承于Person,都有共同的 Kungfu 方法,顯然,我們不能將這個(gè) Kungfu 方法寫到 Person 類,不然隨便一個(gè)路人甲繼承了 Person 類,就擁有了 Kungfu 技能。

用Trait就能解決此問題:

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

class Person {
    public function eat() {
        echo "我是人,我能吃飯<br />";
    }
}

class GuoJing extends Person {
    use Tool;
}

class XiaoFeng extends Person {
    use Tool;
}

$guojing = new GuoJing();
$xiaofeng = new XiaoFeng();

$guojing->kungfu();
$xiaofeng->kungfu();

結(jié)果如下:

降龍十八掌!
降龍十八掌!

方法/屬性的重寫

如果Trait類、基類和本類中的方法或?qū)傩酝?,最終會(huì)以哪個(gè)為準(zhǔn)?

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

class Person {
    public function eat() {
        echo "我是人,我能吃飯<br />";
    }

    public function kungfu() {
        echo "不是每個(gè)人都會(huì)功夫<br />";
    }
}

class GuoJing extends Person {
    use Tool;
    public function kungfu() {
        echo "除了降龍十八掌,我還懂九陰真經(jīng)!<br />";
    }
}

class XiaoFeng extends Person {
    use Tool;
}

$guojing = new GuoJing();
$guojing->kungfu();

結(jié)果:

除了降龍十八掌,我還懂九陰真經(jīng)!

注釋本類的 kungfu 方法,得出的結(jié)果是:

降龍十八掌!

當(dāng)方法或?qū)傩酝麜r(shí),當(dāng)前類中的方法會(huì)覆蓋 trait的 方法,而 trait 的方法又覆蓋了基類中的方法。

組合多個(gè)trait

多個(gè)trait有同名的方法/屬性時(shí),會(huì)報(bào)錯(cuò):

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

trait Skill {
    public function kungfu() {
        echo "渾厚的內(nèi)力修為<br />";
    }
}

class GuoJing {
    use Tool, Skill;
}

$guojing = new GuoJing();
$guojing->kungfu();
Fatal error: Trait method kungfu has not been applied, because there are collisions with other trait methods on GuoJing 

解決方式:使用insteadof和as來解決沖突

  • insteadof: 使用某個(gè)方法替代另一個(gè)

  • as: 給方法取別名

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

trait Skill {
    public function kungfu() {
        echo "渾厚的內(nèi)力修為<br />";
    }
}

class XiaoFeng {
    use Tool, Skill {
        Skill::kungfu insteadof Tool;
        Skill::kungfu as ability;
    }
}

$xiaofeng = new XiaoFeng();
$xiaofeng->ability();
渾厚的內(nèi)力修為

trait方法的訪問控制

as關(guān)鍵詞可以修改方法的訪問控制

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

class XiaoFeng {
    use Tool {
        Tool::kungfu as protected ability; // 修改方法的訪問控制并起別名
    }
}

$xiaofeng = new XiaoFeng();
$xiaofeng->ability();

報(bào)錯(cuò):

Fatal error: Uncaught Error: Call to protected method XiaoFeng::ability() from context

Trait組合

Trait也能組合Trait,同時(shí),Trait中支持抽象方法、靜態(tài)屬性、靜態(tài)方法。

<?php
trait Tool {
    public function kungfu() {
        echo "降龍十八掌!<br />";
    }
}

trait Feature{
    use Tool;
    abstract public function dream();
    public static function character() {
        echo "磊落豪雄 <br />";
    }
}

class XiaoFeng {
    use Feature;
    public function dream() {
        echo "弄清楚:我是誰? <br />";
    }
}

$xiaofeng = new XiaoFeng();
$xiaofeng->kungfu();
XiaoFeng::character();
$xiaofeng->dream();

結(jié)果:

降龍十八掌!
磊落豪雄 
弄清楚:我是誰? 

源碼下載

源碼倉(cāng)庫(kù)鏈接

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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