《現代 PHP》學習筆記(三):Trait

前言

本文為《現代 PHP》一書的學習筆記。

環境

  • Windows 10
  • XAMPP 3.2.2

特徵機制

特徵機制(Trait)是一個局部的類別實作,它可以被混入一個以上的現存類別。

特徵機制的例子如下:

1
2
3
trait MyTrait {
//
}

假想有兩個類別,分別是 RetailStoreCar,它們並沒有相同的母類別,唯一的共通點在於它們都可以被編碼後顯示在地圖上。

要讓這兩個類別有同樣的行為,有三種辦法:

  1. 建立一個共同的父類別 Geocodable,讓 RetailStoreCar 繼承。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Geocodable
{
function setAddress()
{
//
}
}

class RetailStore extends Geocodable
{
//
}

class Car extends Geocodable
{
//
}

但這樣不好,因為這樣強迫了兩個不相關的類別共享了相同的祖先。

  1. 建立一個介面 Geocodable,讓 RetailStoreCar 實作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Geocodable
{
public function setAddress();
}

class RetailStore implements Geocodable
{
public function setAddress()
{
//
}
}

class Car implements Geocodable
{
public function setAddress()
{
//
}
}

這樣好一些,但這不是吻合 DRY 原則的解法。

DRY 是 Do not Repeat Yourself 的縮寫,永遠不要在多個位置重複相同的程式碼。

  1. 建立一個特徵機制 Geocodable,讓 RetailStoreCar 混入。

範例 2-12:Geocodable 特徵機制定義

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
trait Geocodable
{
// 地址(字串)
protected $address;

// 地理編碼物件(來自元件提供的 \Geocoder\Geocoder 的實體)
protected $geocoder;

// 地理編碼器結果物件(來自元件提供的 \Geocoder\Model\AddressCollection 的實體)
protected $geocoderResult;

// 用來插入 Geocoder 物件
public function setGeocoder(\Geocoder\Geocoder $geocoder)
{
$this->geocoder = $geocoder;
}

// 用來設定地址
public function setAddress($address)
{
$this->address = $address;
}

// 用來回傳緯度座標
public function getLatitude()
{
if (!isset($this->geocoderResult)) {
$this->geocodeAddress();
}

return $this->geocoderResult->first()->getLatitude();
}

// 用來回傳經度座標
public function getLongitude()
{
if (!isset($this->geocoderResult)) {
$this->geocodeAddress();
}

return $this->geocoderResult->first()->getLongitude();
}

// 用來將地址字串傳到 Geocoder 實體來取得地理資訊的結果
protected function geocodeAddress()
{
$this->geocoderResult = $this->geocoder->geocode($this->address);

return true;
}
}

如同類別和介面的定義,在每一個檔案中最好只定義一個特徵機制。

範例 2-13:RetailStore 類別定義

1
2
3
4
5
6
class RetailStore
{
use Geocodable;

// 類別實作
}
  • 特徵機制和名稱空間一樣使用 use 關鍵字來匯入,差別在於前者是在類別定義之內匯入特徵空間。

範例 2-14:取得地理資訊結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'vendor/autoload.php';
require 'Geocodable.php';
require 'RetailStore.php';

$adapter = new \Ivory\HttpAdapter\CurlHttpAdapter();
$geocoder = new \Geocoder\Provider\GoogleMaps($adapter);

$store = new RetailStore();
$store->setAddress('Hsinchu City, Taiwan');
$store->setGeocoder($geocoder);

$latitude = $store->getLatitude();
$longitude = $store->getLongitude();

echo $latitude, ':', $longitude;

參考資料

  • Josh Lockhart(2015)。現代 PHP。台北市:碁峯資訊。