PHP 多繼承方法總結(jié)與思考

1、繼承單接口方式

interface testA{ 
    function echostr(); 
}  
interface testB extends testA{ 
    function dancing($name); 
}  
class testC implements testB{ 
 
    function echostr(){ 
        echo "接口繼承,要實(shí)現(xiàn)所有相關(guān)抽象方法!"; 
        echo "<br>"; 
    }  
 
    function dancing($name){ 
        echo $name."正在跳舞!";  
    }  
}  
$demo=new testC(); 
$demo->echostr(); 
$demo->dancing("模特");  
    
//運(yùn)行結(jié)果
/**
    接口繼承,要實(shí)現(xiàn)所有相關(guān)抽象方法
    模特正在跳舞!
**/

//還有另外一個(gè)例子
interface UserInterface{ //定義User的接口
    function getname();
}
interface TeacherInterface{ //teacher相關(guān)接口
    function getLengthOfService();
}
class User implements UserInterface { //實(shí)現(xiàn)UserInterface接口
    private $name = "tom";
    public function getName(){
        return $this->name;
    }
}
class Teacher implements TeacherInterface { //實(shí)現(xiàn)TeacherInterface接口
    private $lengthOfService = 5; // 工齡 
    public function getLengthOfService(){
        return $this->lengthOfService;
    }
}
// 繼承自User類,同時(shí)實(shí)現(xiàn)了TeacherInterface接口.
class GraduateStudent extends User implements TeacherInterface {
    private $teacher ;
    public function __construct(){
        $this->teacher = new Teacher();     
    }   
    public function getLengthOfService(){
        return $this->teacher->getLengthOfService();
    }
}
class Act{
    //注意這里的類型提示改成了接口類型
    public static function getUserName(UserInterface $_user){
        echo "Name is " . $_user->getName() ."<br>";
    }
    //這里的類型提示改成了TeacherInterface類型.
    public static function  getLengthOfService(TeacherInterface $_teacher){
        echo "Age is " .$_teacher->getLengthOfService() ."<br>";
    }
}
$graduateStudent = new GraduateStudent();
Act::getUserName($graduateStudent);
Act::getLengthOfService($graduateStudent);
//結(jié)果正如我們所要的,實(shí)現(xiàn)了有多重身份的一個(gè)對(duì)象.

2、繼承多接口方式

interface testA{
    function echostr();
}
 
interface testB{
    function dancing($name);
}
 
interface testC extends testA,testB{
    function singing($nickname);
}
 
class testD implements testC{
 
    function echostr(){
        echo "接口繼承,要實(shí)現(xiàn)父接口所有相關(guān)方法!";
        echo "<br />";
    }
 
    function dancing($name){
        echo $name."正在跳舞!";
        echo "<br />";
    }
 
    function singing($nickname){
        echo $nickname."正在唱歌!";
    }
}
 
$demo=new testD(); 
$demo->echostr(); 
$demo->dancing("模特");  
$demo->singing("周杰倫"); 
 
//運(yùn)行結(jié)果
/**
    接口繼承,要實(shí)現(xiàn)父接口所有相關(guān)方法!
    模特正在跳舞!
    周杰倫正在唱歌!
**/

需要注意的是當(dāng)你接口繼承其它接口時(shí)候,直接繼承父接口的靜態(tài)常量屬性和抽象方法,所以類實(shí)現(xiàn)接口時(shí)必須實(shí)現(xiàn)所有相關(guān)的抽象方法

3、使用trait

  • 自php5.4.0起,php實(shí)現(xiàn)了一種代碼復(fù)用的方法稱為trait.
  • Trait是為類似php的單繼承語言所準(zhǔn)備的一種代碼服用機(jī)制。Trait為了減少單繼承語言的限制,使開發(fā)人員能夠自由地在不同層次結(jié)構(gòu)內(nèi)獨(dú)立的類復(fù)用method. Trait 和Class 組合的語義定義了一種減少復(fù)雜性的方式,避免傳統(tǒng)的多繼承和 Mixin 類相關(guān)典型問題。
  • Trait 和 Class 相似,但僅僅旨在用細(xì)粒度和一致的方式來組合功能。 無法通過 trait 自身來實(shí)例化。它為傳統(tǒng)繼承增加了水平特性的組合;也就是說,應(yīng)用的幾個(gè) Class 之間不需要繼承。
  • 優(yōu)先級(jí):從基類繼承的成員被 trait 插入的成員所覆蓋。優(yōu)先順序是來自當(dāng)前類的成員覆蓋了 trait 的方法,而 trait 則覆蓋了被繼承的方法。
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;

}

$o = new MyHelloWorld();
$o->sayHello();
//通過逗號(hào)分隔,在 use 聲明列出多個(gè) trait,可以都插入到一個(gè)類中。

4、通過組合模擬多重繼承

class User {
    private $name = "tom";
    public function getName(){
        return $this->name;
    }
}
class Teacher{
    private $lengthOfService = 5; // 工齡 
    public function getLengthOfService(){
        return $this->lengthOfService;
    }
}
// 上面的類中的set方法就不寫了.
// 如果有個(gè)研究生,既是學(xué)生也算工齡. 
class GraduateStudent extends User {
    private $teacher ;
    public function __construct(){
        $this->teacher = new Teacher();     
    }   
    public function getLengthOfService(){
        return $this->teacher->getLengthOfService();
    }
}
$graduateStudent = new GraduateStudent();
echo "name is ".$graduateStudent->getName()."<br>";
echo "lengthOfService is ".$graduateStudent->getLengthOfService();

5、利用__call & 回調(diào)函數(shù)實(shí)現(xiàn)

其中使用的兩個(gè)函數(shù)可以關(guān)注下,然后別忘了,恢復(fù)__call默認(rèn)行為
is_callable
call_user_func_array

class Parent1 {
    function method1() {}
    function method2() {}
}
class Parent2 {
    function method3() {}
    function method4() {}
}
class Child {
    protected $_parents = array();
    public function Child(array $parents=array()) {
        $this->_parents = $parents;
    }
     
    public function __call($method, $args) {
        // 從“父類"中查找方法
        foreach ($this->_parents as $p) {
            if (is_callable(array($p, $method))) {
                return call_user_func_array(array($p, $method), $args);
            }
        }
        // 恢復(fù)默認(rèn)的行為,會(huì)引發(fā)一個(gè)方法不存在的致命錯(cuò)誤
        return call_user_func_array(array($this, $method), $args);
    }
}
$obj = new Child(array(new Parent1(), new Parent2()));
print_r( array($obj) );die;
$obj->method1();
$obj->method3();

補(bǔ)充內(nèi)容 - 接口

  • 接口是什么?
    使用接口(interface),可以指定某個(gè)類必須實(shí)現(xiàn)哪些方法,但不需要定義這些方法的具體內(nèi)容。
    接口是通過 interface 關(guān)鍵字來定義的,就像定義一個(gè)標(biāo)準(zhǔn)的類一樣,但其中定義所有的方法都是空的。
    接口中定義的所有方法都必須是公有,這是接口的特性。

  • 什么時(shí)候用接口?
    1、定規(guī)范,保持統(tǒng)一性;
    2、多個(gè)平級(jí)的類需要去實(shí)現(xiàn)同樣的方法,只是實(shí)現(xiàn)方式不一樣

  • 接口使用規(guī)范

    • 接口不能實(shí)例化
    • 接口的屬性必須是常量
    • 接口的方法必須是public【默認(rèn)public】,且不能有函數(shù)體
    • 類必須實(shí)現(xiàn)接口的所有方法
    • 一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口,用逗號(hào)隔開
    • 接口可以繼承接口【用的少】

思考問題:

所以,我們到底為什么要使用多繼承?

emmm,這是個(gè)好問題,因?yàn)槲覜]有答案,當(dāng)然可能是我還沒有遇到過必須使用多繼承的場(chǎng)景。
不過就目前見識(shí)來看,接口,抽象類已經(jīng)很足夠使用了,所以私以為,可能多繼承主要應(yīng)用場(chǎng)景是一些遺留問題吧?歡迎看官指正了。

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

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