PHP中traits的作用和使用

PHP中traits的作用和使用

traits是在5.4中新增的一個用於實現代碼重用的方法。

php是一種單一繼承的語言,我們無法像java一樣在一個class中extends多個基類來實現代碼重用,現在Traits能解決這一代碼重用的問題,它能讓開發者在多個不同的class中實現代碼重用。
Traits和class在語義的定義上都是爲了減少代碼的複雜性,避免多重繼承的問題。

Traits 和class相似,但是僅用於以統一和較細粒度的方式來提供一組功能,在Traits內部無法進行實例化,即不存在類似class的構造函數__construct()。Traits作爲一個php傳統繼承的擴展並實現水平集成;因此,在應用程序的class中可以不再需要繼承。

1)如何使用
在類中用關鍵字'use' 來引用 Traits。多個Traits 用','隔開。
實例代碼如下:

<?php
trait ezcReflectionReturnInfo {
function getReturnType() {
}
function getReturnDescription() {
}
}class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>

2)優先級
基類中的成員函數將被Traits中的函數覆蓋,當前類中的成員函數將覆蓋Traits中的函數。

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo "World!\n";
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

class MyHelloWorldExt extends Base {
    use SayWorld;
    public function sayHello() {
        /**
         * 這裏是5.4中的新的改動,5.4之前的版本會提示:
         * PHP Fatal error:  Cannot use string offset as an array
         * 5.4中改進爲返回字符串中的該索引號的字符
         */
        $str  = "Arvin";
        echo $str[0][0];// echo 'A';
}

    public function shortArray() {
        $array = ['first', 2, 3, 4];//5.4中的數組簡單語法
        echo $array[0];//5.4中的數組解引用取數組元素方法
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$oe = new MyHelloWorldExt();
$oe->sayHello();
echo "\n";
$oe->shortArray();
輸出:
Hello World!
A
first

3)多Traits

多個Traits可以添加到一個class的聲明中,多個Traits之間用","隔開。

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();

輸出結果:
Hello World

4)多Traits衝突
如果添加到同一個class的兩個Traits中有相同的函數名稱,且沒有明確的進行處理,將產生一個錯誤。
爲了解決同一個類中兩個Tratis中的同名函數衝突,需要用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;
}
}

上面的例子中,Talker使用Traits A 和B,因此兩者中相同的函數名稱存在衝突。
alker中定義了smallTalk取自Traits B,bigTalk取自Traits A。
Aliased_Talker中通過使用as操作符來確保Traits B中的bigTalk通過別名talk來實現。

5)改變函數訪問權限
我們可以使用as語法來改變Traits中函數的訪問權限屬性。

<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}

// Change visibility of sayHello,改變sayHello的訪問權限。
class MyClass1 {
use HelloWorld { sayHello as protected; }
}

// Alias method with changed visibility
// sayHello visibility not changed,設置別名myPrivateHello。
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}

6)Traits組成新Traits
就像許多類一樣可以在類中使用Traits,Traits中一樣可以使用Traits。可以在一個Traits中定義一個或者多個Traits,這些Traits 可以作爲部分或者全部成員被定義在其他Traits中。

<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}

trait World {
public function sayWorld() {
echo 'World!';
}
}

trait HelloWorld {
use Hello, World;
}

class MyHelloWorld {
use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();

以上例程會輸出:Hello World!

7)抽象Trait成員
爲了在類中強制實現某些方法,可以在Traits中使用抽象方法。
例如:

<?php
trait Hello {
    public function sayHelloWorld() {
        echo 'Hello '.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function __construct($world) {
        $this->world = $world;
    }
    public function getWorld() {
        return $this->world;
    }
}

/**
 * 這裏用到了5.4新功能 類實例化解引用操作
 * (new class())->method();
 */
(new MyHelloWorld('Arvin'))->sayHelloWorld();
?>

該實例輸出:
Hello Arvin

8)靜態Trait成員
在Traits中不能定義static 靜態變量,但是可以定義在Tratis的函數中。Tratis中同樣可以定義靜態函數。

<?php
trait Counter {
    public function inc() {
        static $c = 0;//靜態變量
        $c += 1;
        echo "$c\n";
    }
    /**
     * 靜態方法
     */
    public static function doSomething() {
        echo 'Doing something';
    }
}

class C1 {
    use Counter;
}

(new C1())->inc(); // echo 1
C1::doSomething();
?>
輸出爲:
1
Doing something

9) Traits 定義屬性
如果在一個trait中定義了一個屬性,則在引用該trait的類中不能定義同名的屬性,如果該類中定義有和trait中已定義屬性具有相同的名字和訪問可見性,則是一個E_STRICT 提示,否則拋出語法錯誤。

<?php
trait PropertiesTrait {
    public $x = 1;
    public $y = 2;
}

class PropertiesExample {
    use PropertiesTrait;
    public $x = 1;
    //public $y = 3;
}

$example = new PropertiesExample;
echo $example->x, $example->y;
?>

輸出:
12
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章