PHP中Trait特性

飛鴻影~發表於2016-04-22

Trait是自 PHP 5.4.0 起新增的一個新特性,是 PHP 多重繼承的一種解決方案。例如,需要同時繼承兩個 Abstract Class, 這將會是件很麻煩的事情,Trait 就是為了解決這個問題。

下面是一個例子,類Demo同時繼承了Test1Test2

<?php
trait Test1{
    public function add($a, $b){
        echo $a + $b;
    }
}

trait Test2{
    public function sub($a, $b){
        echo $a - $b;
    }
}

class Demo{
    use Test1,Test2;
}

$obj = new Demo();
$obj->add(3, 5); // 8

$obj->sub(3, 5); // -2

一些特性

1、優先順序:當前類 > trait > 基類 。 即當前類中的方法會覆蓋 trait 方法,而 trait 方法又覆蓋了基類中的方法。
2、多個 trait: 通過逗號分隔,在 use 宣告列出多個 trait,可以都插入到一個類中。
3、衝突的解決:
如果兩個 trait 都插入了一個同名的方法,如果沒有明確解決衝突將會產生一個致命錯誤。
為了解決多個 trait 在同一個類中的命名衝突,需要使用 insteadof 操作符來明確指定使用衝突方法中的哪一個。
以上方式僅允許排除掉其它方法,as 操作符可以將其中一個衝突的方法以另一個名稱來引入。

<?php
trait A {
    public function smallTalk() {
        echo `a`;
    }
    public function bigTalk() {
        echo `A`;
    }
}

trait B {
    public function smallTalk() {
        echo `b`;
    }
    public function bigTalk() {
        echo `B`;
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>

4、trait巢狀:Trait 之間也可以相互的巢狀:在 trait 定義時通過使用一個或多個 trait,它能夠組合其它 trait 中的部分或全部成員。
5、Trait 的抽象方法:我們可以在 Trait 中宣告需要實現的抽象方法,這樣能使使用它的 Class 必須實現它。

需要注意的幾點

Trait 會覆蓋呼叫類繼承的父類方法
Trait 無法如 Class 一樣使用 new 例項化
單個 Trait 可由多個 Trait 組成
在單個 Class 中,可以使用多個 Trait
Trait 支援修飾詞(modifiers),例如 final、static、abstract
我們能使用 insteadof 以及 as 操作符解決 Trait 之間的衝突

一些看法

坦白講,第一眼看到 Trait 對它並沒有任何好感。PHP5 以來帶來的新特性已經足夠得多,而且讓開發者們有點應接不暇。

同時,Trait 更像是程式設計師的“語法糖”,然而它提供便利的同時可能會造成巨大的隱患。

針對類中已經實現的方法,Trait 沒有效果。

探討

那麼 Trait 的出現是為何呢?有網友的回答比較有意思,但不無道理:

因為php沒有javascript作用域鏈的機制,所以無法把function bind到class裡面,曾經以為php 5.3的閉包可以做這個事,最後才發覺作用域的設計不允許這麼幹。


相關文章