前言
本文為《現代 PHP》一書的學習筆記。
環境
特徵機制
特徵機制(Trait)是一個局部的類別實作,它可以被混入一個以上的現存類別。
特徵機制的例子如下:
假想有兩個類別,分別是 RetailStore
和 Car
,它們並沒有相同的母類別,唯一的共通點在於它們都可以被編碼後顯示在地圖上。
要讓這兩個類別有同樣的行為,有三種辦法:
- 建立一個共同的父類別
Geocodable
,讓 RetailStore
和 Car
繼承。
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 { }
|
但這樣不好,因為這樣強迫了兩個不相關的類別共享了相同的祖先。
- 建立一個介面
Geocodable
,讓 RetailStore
和 Car
實作。
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 的縮寫,永遠不要在多個位置重複相同的程式碼。
- 建立一個特徵機制
Geocodable
,讓 RetailStore
和 Car
混入。
範例 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;
protected $geocoder;
protected $geocoderResult;
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(); }
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。台北市:碁峯資訊。