php繼承---trait代碼復用


 思考:php中繼承是單繼承,如果某個類有成員要被其他類使用,就需要成為其他類的父類才行,這樣可能會導致繼承鏈會長,合適嗎?

引入:從繼承的角度出發,繼承鏈可以解決問題,但是的確效率會打折扣,同時,如果某些功能是共性使用,但是並不符合繼承條件(不屬於同一類)

那么使用繼承也有所違背面上對象規則,此時可以使用php提供的另外一種代碼復用技術trait

 

trait代碼復用【掌握】

定義:trait是為類似php的單繼承語言而准備的一種代碼復用機制,trait可以使單繼承語言為了復用而不得不繼承的尷尬,讓面向對象更加純粹

1.trait是一種類似class的關鍵字

<?php


// 定義trait
trait show{

}

2.trait內部可以像類一樣擁有成員屬性(包含靜態),成員方法(包含靜態),但不能有常量

<?php


// 定義trait
trait show{
    public $name;

    protected $host;                           //允許定義,但實際不用
    private $info; 

    public function show_time(){ 
        echo $this->info;
    }

    protected function showhost(){                //允許定義,但實際不用
        echo $this->name;
    }

    const pi=3.1415926;                //錯誤  trait中不能有常量
}

3.trait是用來實現代碼的復用的,不可以被實例化也不可以被繼承

<?php


// 定義trait
trait show{
    public $name;

    protected $host;                           //允許定義,但實際不用
    private $info; 

    public function show_time(){ 
        echo $this->info;
    }

    protected function showhost(){                //允許定義,但實際不用
        echo $this->name;
    }


}


new show();                //trait 不允許被實例化

4.trait是用來將公共代碼提供給其他類使用的,而類要使用trait的掐你是加載對應的trait

<?php


// 定義trait
trait Show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}



//類中加載trait
class add{
    //加載:使用use關鍵字
    use Show;           //use 就表示將trait show中所有的東西拿到了當前類add中
}


//使用trait中的內容
$s=new add();
$s->show_time();                //show add類中自己沒有show_time方法,但是因為使用了trait show 所以可用

5.一個類可以使用多個trait

<?php


// 定義trait
trait Show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function get_age(){
        echo $this->age;
    }
}



//類中加載trait
class add{
    //加載:使用use關鍵字
    use Show;           //use 就表示將trait show中所有的東西拿到了當前類add中
    use get;
}


//使用trait中的內容
$s=new add();
$s->show_time();                //show add類中自己沒有show_time方法,但是因為使用了trait show 所以可用
$s->get_age();

 6.如果同時引入的多個trait中有同名方法,那么會產生沖突:解決沖突的方法是使用insteadof代替處理以及對被代替的方法使用別名

<?php


// 定義trait
trait show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function show_time(){
        echo $this->age;
    }
}



//類中加載trait
class add{

    // use get,show;                 //錯誤 2個trait存在同名的方法

    // 方案1 使用其中一個同名方法
    use get,show{
        // 意思 使用show中的show_time 代替get中的show_time,並且會被覆蓋無法使用
        show::show_time insteadOf get;
        // 方案2 給get中的show_time取一個別名  就可以使用了。
        get::show_time as show_insteadostime;
    }
}

$s=new add();
$s->show_time();            //輸出的是d  而不是18  代替成功
$s->show_insteadostime();       //顯示18

7.同名覆蓋問題:如果類中有與引入的trait同名成員,會有不同處理

  屬性:不允許重名,即類中不允許定於與trait中同名的成員屬性(靜態屬性也一樣)

  方法:類覆蓋trait

<?php


// 定義trait
trait show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function show_time(){
        echo $this->age;
    }
}



//類中加載trait
class add{

    // use get,show;                 //錯誤 2個trait存在同名的方法

    // 方案1 使用其中一個同名方法
    use get,show{
        // 意思 使用show中的show_time 代替get中的show_time,並且會被覆蓋無法使用
        show::show_time insteadOf get;
        // 方案2 給get中的show_time取一個別名  就可以使用了。
        get::show_time as show_insteadostime;
    }
}

$s=new add();
$s->show_time();            //輸出的是d  而不是18  代替成功
$s->show_insteadostime();       //顯示18

8.繼承覆蓋問題:如果類中在使用trait的同時,也是繼承自父類,而trait中與父類中有同名方法,那么trait中將覆蓋父類同名方法,如果要訪問父類方法,

可以在trait同名方法中使用parent關鍵字訪問父類同名方法。

<?php

// 代碼復用
    trait posen{
        public $name="杜偉";
        public $age=31;

        public function show(){
         // 如果想用父類中的方法
         parent::show();
            echo $this->name.$this->age;
        }
    }


// 父類
class human{
    public function show(){

        echo 'human::show<hr>';
    }
 
}

// 定義子類
class son extends human{
    use posen;              
}

// 實例化
$s=new son();
$s->show();               //顯示的是杜偉 31  trait中的方法會覆蓋繼承中父類的方法

9.另外,trait自己不能訪問,只是用來給其他類提供代碼復用的,因此允許類在使用trait時更高里面方法的訪問控制權。在as 之后,使用目標訪問修飾限定符。

<?php

// 代碼復用
    trait posen{
        private function show(){
            echo '你看到我了';
        }
    }

class son{
    use posen{
        //因為我只是引用了一個show,如果是兩個的話  需要具體的體現是哪個 posen::show(這個)
        show as public pshow;              
        //注意 as是用來起別名的,雖然沒有同名show 但是系統認為已經存在,並且改變trait中show的訪問權限為public 變成了一個新的方法,原來的方法不動。
    }              
}

// 實例化
$s=new son();
$s->pshow();           //調用別名方法

10.trait中可以使用抽象方法,用來規范使用類必須實現對應抽象方法,使用了欸要么為抽象類,要么就必須實現抽象方法

<?php

// 代碼復用
    trait posen{
       abstract public function add();            //trait 定義抽象方法
    }


// 第一種方式
abstract class man{
    use posen;                          //抽象類可以不實現抽象方法
}

// 第二種
class son{
    use posen;
    public function add(){
        echo '實現了trait中的抽象方法';          //實現抽象方法
    }
                
}

總結:

  1.trait的hi一種類似class結構關鍵字,trait不能被實例化,可以擁有所有類成員結構

  2.trait是用來實現代碼復用的,為其他類提供公共代碼(方法),其他類如果使用trait用use關鍵字引入

  3.在了類中use是具體trait就相當於將trait內部的所有代碼在類中寫了一遍

  4.一個類中可以有多個trait,但是要注意同名問題

    同名方法可以使用insteadof來實現代替:一個trait中的同名方法代替另外一個,類就訪問替代的那個

    同名方法可以在被替代之后使用as制作方法使用as制作方法別名:類就可以擁有兩個方法

  5.類中在引入trait后,要注意與trait中的同名成員問題

    同名屬性:不允許

    同名方法:允許,類中的方法會覆蓋trait中的方法

  6.如果在使用trait的同時也繼承其他類,那么trait中出現的同名方法會覆蓋基類的同名方法

  7.類在使用trait時可以修改trait方法的控制級別,更嚴或這更寬松都可以,注意修改控制級別時使用的時別名機制,一定要改成別名:trait名::方法名 as 訪問修飾限定符 別名;

  8.trait中可以使用抽象方法,那么使用該trait的類就必須本身為抽象類或者將抽象方法實現

  9.trait使用機制

    有公共代碼要實現(方法),而這些方法可能在很多類中會用到

    公共代碼不是屬於某一類事務特有,而是很多事務都有(不符合繼承)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM