php – 藉由安插特徵 (trait) 來修改父類別 (class) 的方法

當原有的程式碼 class My 繼承 class Base 的時候,若要改變已存在 class Base 的方法,可以藉由安插 trait 的方式,來修改 Base 的原有方法。

<?php
class Bass 
{
    public function hello()
    {
        return "Hello World";
    }
}

trait Action 
{
    public function hello()
    {
        return "Action! " . parent::hello();
    }
}

class My extends Bass
{
    // 一旦添加了特徵 Action ,那麼 Base::hello() 將會被覆蓋。
    use Action;

    public function say()
    {
        return $this->hello();
    }
}

$My = new My;
echo $My->say(); // Action! Hello World

我們在 class My 中添加了

use Action;

那麼 trait 的 Action::hello() 會覆蓋 class 的 Base::hello() 。如果在trait 的 Action::Hello() 要呼叫 class 的 Bass::Hello(),可以藉由

parent::hello()

來達到。這是因為 class My 繼承了 class Bass,中間安插了 trait Action。所以關係上來說是

class Base -> trait Action -> class My

trait Action 的 parent 自然會是 class Base。

php – 使用特徵 trait 定義屬性

直接在 trait 裡面定義即可,寫法如同 class 一樣。

<?php
trait Bag {
    //定義特徵的屬性
    public $color = 'red';
    public $size  = 'small';
}

class Cart {
    use Bag;
}

$Cart = new Cart;
echo $Cart->color; // red
echo $Cart->size; // small

但如果 class 中也定義了 trait 已有的屬性,且屬性質相異,那就會發生錯誤。

trait Bag {
    public $color = 'red';
    public $size  = 'small';
}

class Cart {
    use Bag;
    public $color = 'green'; // 相同不會錯誤
    public $color = 'large'; // 相異發生錯誤
}

 

php – trait 靜態寫法

透過 static 的關鍵字,就可以將特徵的方法,定義為靜態方法,這樣即可由類別直接呼叫。

<?php
trait Profile 
{
    // 添加關鍵字 static 代表靜態方法
    public static function name() 
    {
        return 'Jason';
    }
}

class My {
    use Profile;
}

echo My::name(); // Jason

 

php – 使用 trait 定義抽象方法

<?php 
trait Hello 
{
    // 只在這裡定義抽象方法,確切的實作會寫在 My::get() 
    abstract public function get();

    // 可被呼叫
    public function say()
    {
        echo 'Hello ' . $this->get();
    }   
}

class My
{
    use Hello;

    private $text;

    public function get()
    {
        return $this->text;
    }

    public function set($val)
    {
        $this->text = $val;
    }
}

$My = new My;
$My->set("World");
$My->say(); //Hello World

 

php – 修改原有的特徵 trait 可否被造訪 (public/protected/private)

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

class MyClass1 {
    // 修改了特徵 HelloWorld 的 sayHello() 為保護(protected)
    use HelloWorld { sayHello as protected; }
}

class MyClass2 {
    // 使用 HelloWorld 的 sayHello(),建立一個私有(private)的別名方法叫做 myPrivateHello 
    use HelloWorld { sayHello as private myPrivateHello; }
}

因為被修改為 protected 所以不可被外部訪問

// $MyClass1 = new MyClass1;
// $MyClass1->myPrivateHello();

因為建立了私有別名,所以 sayHello() 仍然可以被訪問;myPrivateHello() 則不行。

$MyClass2 = new MyClass2;
$MyClass2->sayHello(); // 可
$MyClass2->myPrivateHello(); // 不可