導入 Composer
Composer 是目前 PHP 界裡廣泛使用的套件管理工具,用 Composer 的自動載入也會比較容易跟 Laravel 串接。我們今天就來導入 Composer 吧!
Faker 套件使用方法非常單純--使用工廠(Factory
)建構產生器(Generator
),然後把產生器拿來用就對了。
如果有認真翻原始碼的話,會發現它是有經過設計的。內部元件間是鬆耦合狀態,這也表示我們也是能夠簡單地客製化自己的產生器的。
以下會以類別名討論,為節省版面空間,將會把 Faker
命名空間省略。
Factory
是標準的 Simple Factory Pattern 實作,它使用靜態方法 create()
取得固定一種類型的物件--Generator
。類別圖如下:
@startuml |
Generator
是需要經過組裝的,因客戶要求的 $locale
不同,而會有不同的組裝內容。跟現實生活的生產線一樣,組裝 Generator
的任務是交由 Factory
負責的。
Client
,也就是使用 Faker 套件的客戶端,只要使用 Factory::create()
就能保證一定會拿到 Generator
。如果物件組裝過程有問題的話,則會丟例外。
Generator
的 doc block 定義了很多屬性和方法,但會發現裡面完全沒有實作,也就是全靠 __get()
與 __call()
達成目的。
public function __get($attribute) |
接著我們會發現它們裡面用不同的方法呼叫了同一個方法 format()
:
public function format($formatter, $arguments = array()) |
這裡因為 method 參數命名的關係,也搞混了一陣子。後來才發現是這樣的:我們來找 doc block 裡屬性與方法名字一樣的,如 name
與 name()
,然後代入上面的 Magic Method 試試:
public function __get($attribute = 'name') |
這時代入 format()
就會非常容易理解了:
$this->format('name'); |
因此 format()
的任務就很明白了:它會用取到的 Formatter 拿來當 callback 呼叫。
再來翻 getFormatter()
做了什麼:
public function getFormatter($formatter) |
首先最開頭的 if 實作方法,有點類似 Registry of Singleton Pattern--手邊有一系列的物件,但想確保每個物件都是單例。
if (isset($this->formatters[$formatter])) { |
第二段的 foreach
會把所有的 Provider 拿出來一個一個找看看有沒有同名的 method。
foreach ($this->providers as $provider) { |
像剛剛的 name
屬性或方法,實際呼叫會找到 Provider\Person
的 name
方法。接下來會把 callback 設定單例,之後 Client
就能經由 Generator
直接轉接到 Provider\Person
裡的同名函式了。
這是標準 Facade Pattern--所有對 Provider 操作的行為,都隱藏在 Generator 的 getFormatter()
裡面。
而最後如果都找不到的話,就會丟例外:
throw new \InvalidArgumentException(sprintf('Unknown formatter "%s"', $formatter)); |
parse()
的原始碼如下:
public function parse($string) |
看 preg_replace_callback
函式文件說明,第二個參數是 callback,實際呼叫的函式是下面這一個:
protected function callFormatWithMatches($matches) |
這個正則主要會把下面的文字抓出來,然後一個一個丟到 callback:
// 原始文字 |
format()
會接到陣列第二個值,也就是 word1
和 word2
,取代則是整個 pattern 取代。而 format()
前面也追過原始碼了,它會轉接到 Provider 對應的方法。
也許有點難理解,來看看它的測試案例好了:
public function testParseReturnsStringWithTokensReplacedByFormatters() |
它裡面用了一個自定義的 FooProvider
,裡面長這樣:
class FooProvider |
因此這個 Generator
加上 FooProvider
會有這樣的效果:
$generator = new Generator(); |
而使用在 parse()
上則會有這樣的效果:
$generator->parse('This is {{fooFormatter}} a text with {{ fooFormatter }}'); |
講這麼多,其實結論就是:下面這兩段程式碼的效果是一樣的:
echo "你好我是 {$generator->name},這位 {$generator->name} 是我的好朋友\n"; |
輸出結果:
你好我是 Ms. Elissa Schinner,這位 Miss Dannie Mraz II 是我的好朋友 |
其他方法相較單純,像 addProvider()
之類的,就不介紹了。
今天把生線工人 Factory 與產生器 Generator 介紹完了,明天來細看 Provider
的設計。
在開始正式寫假文產生器前,我們先來看看哪些子命令和參數是需要定義的。
我們接下來會使用 PHPConf 2016 的簡報「使用 Slim 為 Legacy Code 重構」提到的 proxy pattern 方法來重構。而中間的 Route 會使用 Laravel。只是在使用 Laravel 之前,我們得先要升級 PHP。
在開發階段時,取名是讓開發者覺得非常困擾的任務之一。
當然,變數或函式命名必須得好好想想,不然容易造成別人看不懂的技術債。但有一種很想亂打就好,但系統會要求你不能亂打的--測試資料。
比方說,前兩天上測試環境要註冊帳號看到:
miles 這個使用者名稱已有人使用,請試試其他名稱。 |
對厚,上禮拜才用這個帳號,那換 miles123
試試:
miles123 這個使用者名稱已有人使用,請試試其他名稱。 |
可…可惡,又重覆了!那 miles482842781937382383724
總沒用過吧
miles482842781937382383724 可以使用哦,揪咪 ^.< |
系統是在揪咪什麼啦!算了,總之而言,註冊好了。
(十分鐘後…)
嗯…剛剛的帳號名稱是什麼?忘了,再註冊一個吧!(上面的故事再循環一次)
又或者是,系統上會有 100 多個姓「麥」的,然後有 50 個都叫「爾斯」,當測試環境出問題的時候,看到「麥爾斯」出錯,還真的不知道是哪一個在搞鬼。
https://www.youtube.com/watch?v=ecjQvXCsVl4
這套件的功能,就是產生假資料,常見的姓名當然難不倒它:
$faker = Faker\Factory::create(); |
再來看看它還可以產生什麼:
// 地址 |
各式各樣的假資料都能產生,不僅如此,它還支援多語系:
$faker = Faker\Factory::create('en_US'); |
輸出可能如下:
Robert Becker |
什麼!區區一個假文產生器怎麼這麼自戀,叫什麼「帥哲哲」!?沒關係,這幾天讓我們一起來一探假文產生器的奧妙,到時要叫「金城武」還是「金秀賢」都隨開發者高興了!
這幾天將會使用 Faker v1.7.1 做範例。
不管程式再怎麼爛,因為之前專題有過關,至少可以它「曾經」跑得起來吧?
今天來繼續看 Carbon 還有擴充哪些功能
Carbon 提供許多比較的方法,讓我們在判斷時間會方便很多。
eq()
lt()
gt()
…這些方法相信許多開發者都有看過。即使沒看過,每一個方法也都有相對應的別名可以參考使用。
between()
min()
max()
這些方法是基於上面的基本比較方法實作出來的。
closest()
farthest()
這兩個方法是基於 DIFFERENCES 功能實作的。
isPast()
isFuture()
is*()
…這些方法因為非常語言化,所以用起來很方便。會這樣設計,是因為我們在平常用詞時,會不自覺使用這些字眼:「這日期過去了嗎?」「這日期是未來嗎?」「這日期是今天嗎?」等等。
而且都可以跟昨天提到的建構方法直接串接:
// 明天是週末嗎? |
如果直接修改字串來調整時間,不知道要寫多少程式碼來判斷例外狀況,像是閏年、大小月等等,但使用 Carbon 就很簡單了:
// 三小時前 |
除了年月日時分秒的計算外,它還有一季(三個月)、一世紀(百年)、週(七天)等等常見的算法。
通常老闆問還有多少天才做得完,那可以用 ADDITIONS 來加日期來跟老闆說哪時會好,但如果是老闆壓時間的話,就得用 DIFFERENCES 來看我們還有多少天可以趕了:
// 跨年前要完成 |
它能把物件的時間調整成如方法描述一樣,比方說:
// 這個月月初 |
翻完 Carbon
程式碼,會發現它實作語意化行為的基礎,是建立在許多基本功能上,比方說加減日期、時間調整和計算差異,這些基本功能可以實作出平常對談的用詞,像是「明天」、「上個月」、「下週」等等。
另外有趣的是,它幾乎所有的方法都是公開的(public),雖然最小知識原則提醒我們最好不要這麼做。但是這三天原始碼看下來,這些方法都是大家一般對時間的認知,因此反而是公開會比較恰當。
最後,這是一個繼承很棒的範例,如果覺得繼承後寫出來的東西不如想像中好用,或許可以參考 Carbon,了解繼承還可以如何寫!
今天開始,我們要一起來面對骯髒的程式碼了。