蕭峯與郭靖教你學會PHP的Trait

圖片描述

在PHP5.4以前,PHP面向對象須要複用代碼的方式是使用類的繼承。但PHP只支持單繼承,在應對較複雜的業務邏輯中,單繼承就顯得捉襟見肘了。php

trait的使用場景

如如下應用場景:git

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 方法,顯然,咱們不能將這個 Kungfu 方法寫到 Person 類,否則隨便一個路人甲繼承了 Person 類,就擁有了 Kungfu 技能。app

用Trait就能解決此問題:spa

<?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();

結果以下:.net

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

方法/屬性的重寫

若是Trait類、基類和本類中的方法或屬性同名,最終會以哪一個爲準?code

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

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

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

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

class XiaoFeng extends Person {
    use Tool;
}

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

結果:對象

除了降龍十八掌,我還懂九陰真經!

註釋本類的 kungfu 方法,得出的結果是:blog

降龍十八掌!

當方法或屬性同名時,當前類中的方法會覆蓋 trait的 方法,而 trait 的方法又覆蓋了基類中的方法。繼承

組合多個trait

多個trait有同名的方法/屬性時,會報錯:圖片

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

trait Skill {
    public function kungfu() {
        echo "渾厚的內力修爲<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: 使用某個方法替代另外一個

  • as: 給方法取別名

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

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

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

$xiaofeng = new XiaoFeng();
$xiaofeng->ability();
渾厚的內力修爲

trait方法的訪問控制

as關鍵詞能夠修改方法的訪問控制

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

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

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

報錯:

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

Trait組合

Trait也能組合Trait,同時,Trait中支持抽象方法、靜態屬性、靜態方法。

<?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();

結果:

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

源碼下載

源碼倉庫連接

相關文章
相關標籤/搜索