前言
本文為《現代 PHP》一書的學習筆記。
環境
特徵機制
特徵機制(Trait)是一個局部的類別實作,它可以被混入一個以上的現存類別。
特徵機制的例子如下:
假想有兩個類別,分別是 RetailStore 和 Car,它們並沒有相同的母類別,唯一的共通點在於它們都可以被編碼後顯示在地圖上。
要讓這兩個類別有同樣的行為,有三種辦法:
- 建立一個共同的父類別 Geocodable,讓RetailStore和Car繼承。
| 12
 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實作。
| 12
 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 特徵機制定義
| 12
 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 類別定義
| 12
 3
 4
 5
 6
 
 | class RetailStore{
 use Geocodable;
 
 
 }
 
 | 
- 特徵機制和名稱空間一樣使用 use關鍵字來匯入,差別在於前者是在類別定義之內匯入特徵空間。
範例 2-14:取得地理資訊結果
| 12
 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。台北市:碁峯資訊。