1. 程式人生 > >PHP Trait

PHP Trait

PHP5.4實現了一種程式碼複用的方法稱為Trait。Trait為了減少單繼承語言的限制,能夠自由地在不同層次結構內獨立的類中複用方法,Trait和Class組合的語義定義了一種減少複雜性的方式,避免傳統多繼承和 Mixin 類相關典型問題。無法通過 trait 自身來例項化。一個類要應用trait需要使用use關鍵字,一個類可以應用多個trait,只需要在use關鍵字後用逗號分隔多個trait。trait中也可以應用其他的trait。

<?php
trait a{
    function getA(){
        return "a";
    }
}
trait b{
    function getB(){
        return "b";
    }
}
class Test{
    use a,b;
}
$test=new Test();
echo $test->getA()."\n";
echo $test->getB()."\n";

trait c{
    use a,b;
}
class Test2{
    use c;
}
$test=new Test2();
echo $test->getA()."\n";
echo $test->getB()."\n";
?>

如果trait和class中存在相同的成員,則優先順序規則為,當前類的成員->trait的成員->繼承的成員。

<?php
trait a{
    function getA(){
        parent::getA();
        echo "a in trait\n";
    }
}
class Base{
    function getA(){
        echo "a in Base\n";
    }
}
class Test extends Base{
    use a;
}
class Test2 extends Base{
    use a;
    function getA(){
        echo "a in Test2\n";
    }
}
$test=new Test();
$test->getA();

$test2=new Test2();
$test2->getA();
?>

在應用多個trait時,如果插入了同名的方法,則需要解決衝突,否則會產生致命錯誤。解決衝突可以使用insteadof關鍵字來指明使用哪一個方法。還可以通過as關鍵字為某個方法引入別名,as關鍵字還可以調整方法的訪問控制。

<?php
trait A {
    public function printLower() {
        echo 'a';
    }
    public function printUpper() {
        echo 'A';
    }
}

trait B {
    public function printLower() {
        echo 'b';
    }
    public function printUpper() {
        echo 'B';
    }
    public function testAccess(){
        
    }
}

class Test {
    use A, B {
        B::printLower insteadof A;
        A::printUpper insteadof B;
        B::printUpper as private upper;
        testAccess as protected;
    }
}

$test=new Test();
$test->printLower();
$test->printUpper();
//$test->upper();
//$test->testAccess();
?>

trait還支援抽象方法,應用trait的類需要實現抽象方法,否則會產生致命錯誤。trait還支援靜態成員。

<?php
trait a{
    function lower(){
        return "a";
    }
    abstract function upper();
    public static function foo(){
        echo "static function foo\n";
    }
}
class Test{
    use a;
    function upper(){
        return "A";
    }
}
$t=new Test();
echo $t->lower()."\n";
echo $t->upper()."\n";
Test::foo();
?>

trait中可以定義屬性,但是應用trait的類不能定義與之同名的屬性,否則會產生致命錯誤,除非屬性是相容的,即訪問控制和初始預設值都相同。PHP7.0之前即使屬性相容也會有E_STRICT的提醒。

<?php
trait a{
    public $var="a";
    public $diff1="a";
    public $diff2="a";
}
class Test{
    use a;
    public $var="a";
    //public $diff1="b";
    //protected $diff2="a";
}
?>