序言 - 碁峰資訊epaper.gotop.com.tw/pdfsample/a434.pdf · php...

17
現在網路上有數以萬計的 PHP 教學,但絕大部分都已過時而且示範了不良的習慣。不 幸的是,因為 Google 搜尋引擎的存在,我們依然不停地搜尋到這些過時的教學。過時 的資訊對於不夠細心的 PHP 程式設計師來說非常危險,因為他們會不自覺地實作出低 效率且安全性不足的 PHP 應用程式。我在 2013 年的時候察覺到了這個問題,而這就是 我開始 PHP The Right Way 社群(http://www.phptherightway.com/)的主要原因,這個 社群提供 PHP 程式設計師一個方便的管道去接觸到由受認證成員所提供的最新並且高 水準的資源。 《現代 PHP是我對於這個相同目標努力嘗試的第二件事,這本書並不是一本參考指 南,相反的,我的描述方法是與讀者做一個友善且有趣的對話。我將會為讀者介紹現代 PHP 程式語言,展示我每天在工作和開源專案中使用的最新 PHP 技術,還會幫助你 應用最新的程式碼標準,讓你可以在 PHP 的社群中分享自己的 PHP 元件函式庫。 聽到我一遍又一遍地提到社群,事實上 PHP 社群是一個友善、有幫助並且歡迎人們加 入的地方(雖然並非沒有發生一些偶然的爭執),如果你對於一些書中提到的特色感到 好奇,嘗試帶著你的問題接觸你當地的 PHP 社群,我保證周遭的 PHP 開發者會很樂意 幫助你成為更好的 PHP 程式設計者。在讀完這本書後,周遭的 PHP 社群是個可以讓你 持續增進 PHP 技術的無價資源。 序言

Upload: others

Post on 15-Jun-2020

8 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

現在網路上有數以萬計的 PHP教學,但絕大部分都已過時而且示範了不良的習慣。不幸的是,因為 Google搜尋引擎的存在,我們依然不停地搜尋到這些過時的教學。過時的資訊對於不夠細心的 PHP程式設計師來說非常危險,因為他們會不自覺地實作出低效率且安全性不足的 PHP應用程式。我在 2013年的時候察覺到了這個問題,而這就是我開始 PHP The Right Way社群(http://www.phptherightway.com/)的主要原因,這個社群提供 PHP程式設計師一個方便的管道去接觸到由受認證成員所提供的最新並且高水準的資源。

《現代 PHP》是我對於這個相同目標努力嘗試的第二件事,這本書並不是一本參考指南,相反的,我的描述方法是與讀者做一個友善且有趣的對話。我將會為讀者介紹現代

的 PHP程式語言,展示我每天在工作和開源專案中使用的最新 PHP技術,還會幫助你應用最新的程式碼標準,讓你可以在 PHP的社群中分享自己的 PHP元件函式庫。

聽到我一遍又一遍地提到社群,事實上 PHP社群是一個友善、有幫助並且歡迎人們加入的地方(雖然並非沒有發生一些偶然的爭執),如果你對於一些書中提到的特色感到

好奇,嘗試帶著你的問題接觸你當地的 PHP社群,我保證周遭的 PHP開發者會很樂意幫助你成為更好的 PHP程式設計者。在讀完這本書後,周遭的 PHP社群是個可以讓你持續增進 PHP技術的無價資源。

序言

Page 2: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

序言 │ xiii

關於本書

在我開始之前,想先說明一些我預期的事。首先,我們沒有足夠的時間,所以這本書不

可能涵蓋使用 PHP的每一種方式。相反的我會讓你看到我如何使用 PHP。對,這是一種自以為是的方式,但是我使用的是其他很多 PHP開發者同樣採納的習慣和標準,在讀完本書後你帶走的將是一些可以立刻應用在自己專案上的東西。

其次,我假設你已經熟悉變數、流程控制、迴圈等等的概念,你不必知道怎麼寫 PHP,但是至少應該對於這些基本的程式語言概念有些認識,當然在閱讀的同時還可以同時帶

上一杯咖啡(我也熱愛咖啡),而我將會提供任何其他你所需要的。

再者,我並沒有假設你使用的是特定的作業系統,但是我的程式碼範例是針對 Linux環境的,Bash環境是Ubuntu和CentOS系統所提供的,而大概在OS X系統中也可以使用,如果你使用的是Windows,我強烈建議你安裝 Linux虛擬主機,這樣你就可以執行這本書上的範例程式碼。

本書結構

第一部分說明了新的 PHP特點,例如名稱空間 (Namespaces)、產生器 (Generator)、和特徵機制 (Traits),這個部分介紹了現代的 PHP程式語言,並且讓你發現一些至今可能都還不知道的特性。

第二部分介紹了一些應當要實作在 PHP應用程式中的良好習慣,你有聽過 PSR這個專

有名詞但是不確定它是甚麼以及如何使用它?想知道如何消毒 (sanit ize)使用者的輸入以及確保資料庫查詢的安全性?那麼,這個章節是為你而寫的。

第三部分將會有更多關於說明技術的部分,其中說明了如何部屬、調校、測試及剖析

PHP應用程式,我們將跟 Capistrano一同研究 PHP應用程式的開發策略,我們會談到測試的工具,例如 PHPUnit和 Travis CI,還會一同探索如何有效的調整 PHP應用程式的效能。

附錄 A提供了如何在你的電腦上安裝和配置 PHP-FPM的詳細指引。

附錄 B解釋了如何在一個本地開發環境建立一個生產伺服器,為了幫助你更快上手,我們介紹了 Vagrant、Puppet、Chef以及一些替代工具。

Page 3: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件

第四章

越來越少的大型框架存在於現代的 PHP之中,反而我們更常利用可互通的專門元件來組合出適當的工具,當我建立新的 PHP應用程式時,我很少直接使用 Laravel或Symfony,相反的,我會思考自己可以組合哪些現有的 PHP元件,用來解決我的問題。

為何要使用元件?

現代 PHP的元件對於很多 PHP開發者來說是個新概念,直到幾年前我才稍微了解 PHP元件,在我了解 PHP元件的知識之前,我都直接使用像是 Symfony或是 CodeIgniter之類的大型框架,完全沒有考慮其他的選擇,我把所有的時間花在單一框架的生態系統

中,並且使用它提供的工具,如果這個框架沒有提供我需要的工具,我只能自認倒楣並

且自己實作額外的功能,對於大型框架來說,整合自製的或是第三方函示庫也很困難,

因為它們通常沒有使用共通的介面。我可以輕鬆告訴你這個時期已經過去了,現在我們

將不再被大型框架的高牆所束縛。

現今,我們從為數眾多的元件中選擇適合的來創造自製的應用程式,為何我們要浪費

時間在編寫處理 HTTP請求和回應的程式碼,而非直接使用早已存在的 guzzle/http

(https://packagist.org/packages/guzzle/http)元件?當 aura/router(https://packagist.org/packages/aura/router)和 orno/route(https://packagist.org/packages/orno/route)元件可以解決你的問題,為何要建立一個新的路由器?為何要花時間寫一個和 Amazon S3線上存儲服務溝通的橋樑,而非直接使用 aws/aws-sdk-php(https://packagist.org/packages/aws/aws-sdk-php)和 league/flysystem(https://packagist.org/packages/league/flysystem)?你懂我的意思,其他的開發者花了數不清的時間建立、最佳化和測試專門的元件,用來完美處理某一件事,如果不善加利用這些元件來建立更好的應用程式,反

而是重複先人的工作,那我只能說你是傻子了。

Page 4: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

52 │ 第四章

什麼是元件?

在 PHP應用程式中,元件是一組用來解決特定問題的程式碼,舉例來說,如果你的PHP應用程式需要發送和接收 HTTP請求,就有特定的元件為此存在;如果你的 PHP應用程式需要解析逗號分隔值資料,也有特定的元件為此存在;如果你的 PHP應用程式需要一個紀錄資訊的方法,也有特定的元件為此存在。我們不會為了已解決的問題實

作新的功能,而是使用 PHP元件並且把目標放在解決我們專案中更大的目標。

技術上來說,PHP 元件是一套用來解決一個問題的相關類別、介面和特徵機制。

而它們通常位於共同的名稱空間之下。

在任何市場都有不同素質的產品,同樣的道理在 PHP元件中也說得通,就像是你在雜貨店中挑蘋果一樣,你有幾招訣竅可以辨別一個 PHP元件的好壞,以下是數個優良PHP元件的特性:

聚焦

PHP元件必須聚焦在單一的問題之上並且完善地解決,元件並不能樣樣通樣樣鬆,而是要成為只為一個問題而存在的專家,並且使用簡單的使用者介面包裝其內部的

設計。

小型

PHP元件不能有任何的累贅,它只包含了最小限度的程式碼用來解決應當解決的問題,而這個限度依情況而定,PHP元件可以只含有一個 PHP類別,也可以有子名稱空間包含數個 PHP類別。PHP元件所包含類別的數量並沒有絕對正確的答案,必要時也能使用多個類別只為了解決單一問題。

合作

PHP元件跟其他元件中可以良好的銜接,畢竟這是 PHP元件最根本的目標:存在就是為了與其他元件一同合作組合出更大的工具,PHP元件並不會用自身的程式碼汙染全域空間,相對的 PHP元件存在於自有的名稱空間中,以避免跟其他元件有名稱上的重複。

適當的測試

PHP元件將經過適當的測試。歸功於小而美的設計,這通常很容易達成。如果一個PHP元件維持小型並且聚焦於單一問題,它將會非常容易被測試,需要被擔心的問

Page 5: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 53

題很少,相依性也很容易被確定,最好的 PHP元件提供它們自身的測試工具以及有足夠的程式碼覆蓋率。

良好的文件

PHP元件將需要有良好的文件,必須可以輕易被開發者安裝、了解並且使用,良好的文件可以促成這一切目標,PHP元件應當要有一個 README檔案來說明元件的用途、安裝方式以及使用方法,可能也有網頁來說明更深入的訊息。而良好的文件同

樣應當存在於元件的原始碼之中,類別、方法、和屬性之間都應該有註釋來說明程

式碼、參數、回傳值和潛在的例外。

元件和框架

框架(特別是大型框架)的問題是使用它們需要投入大量的心力,當我們選擇了一個框

架,必須花費時間研究框架的工具,框架通常都提供了各式各樣的工具,但有時我們需

要的恰巧是框架沒有提供的工具,這就成了一種負擔,我們必須尋找並整合客制的框

架,整合第三方的程式碼到框架中很困難,因為它們之間通常沒有使用共通的介面。

當我們挑選框架時,等同於投資了這個框架的未來,我們對於框架的核心開發團隊抱持

信念,我們假設框架開發者會持續的花時間開發此框架,並確保框架中的程式碼持續兼

容於最新的標準,而這件事常常不會發生,框架非常龐大,需要很多時間和精力去維護,

框架的保有者都擁有它們各自的生活、工作和興趣,而這些事情不會永遠保持不變。

老實說,大型的 PHP 元件同樣有被拋棄的風險,特別是只有單一核心開發者時。

同樣,誰說一個特定框架可以永遠符合我們的需求呢?存在許多年的大型專案必須功能

完整並且適時地為未來而改變,錯誤的 PHP框架有可能阻礙了這項能力,較舊的 PHP框架常因效率漸漸不佳或是失去社群支援而無人使用,它們常使用程序式(procedural)程式風格而非現代的物件導向程式風格,新的團隊成員可能不熟悉舊框架的程式庫。對

於使用 PHP框架與否有太多需要考量的因素。

Page 6: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

54 │ 第四章

框架並非只有缺點

至今我描述了框架的許多缺陷,但框架不全然只有缺點。Symfony(http:/ /symfony.com/)是個現代 PHP 框架的最佳典範,Fabien Potencier 和 Sensio Labs(http:/ /sensiolabs.com/)建立了 Symfony Framework,並將其定義為小型 Symfony元件(http://symfony.com/components)的聚合物,這些元件可以如同框架一般共同使用,也可以單獨的使用在小型的應用程式中。

另外,較舊的框架也朝向現代的 PHP元件轉變,Drupal內容管理框架(https:/ /www.drupal.org/)是另外一個範例,Drupal 7以程序式 PHP程式寫成並且存在於全域名稱空間中,為了支援舊有程式碼而忽略了現代的 PHP習慣,但是 Drupal 8有著邁入現代PHP的令人讚賞的大改變,Drupal 8權衡了它在許多 PHP元件中的優勢,並建立了現代的內容管理平台。

Laravel(http:/ / laravel .com/)是由 Taylor Otwell 建立的熱門 PHP 框架,如同Symfony,Laravel建立於自有的 Illuminate(https://github.com/illuminate)元件庫之上,但是(至本書出版時),Laravel的元件仍不容易的整合在其他非 Laravel的應用程式之中,Laravel並沒有使用PSR-2社群標準,也沒有採取Semantic Versioning scheme(http://semver.org/),但儘管如此,Laravel仍然是一個令人驚艷的框架,可以用來創造威力十足的應用程式。

最熱門的現在 PHP 框架包含了:

y Aura(http://auraphp.com/framework)

y Laravel(http://laravel.com/)

y Symfony(http://symfony.com/)

y Yii(http://www.yiiframework.com/)

y Zend(http://framework.zend.com/)

為工作挑選適當的工具

應該使用元件還是框架?為工作挑選適當的工具,大多數的現代 PHP框架只是一堆小型 PHP元件所組合而成。

如果你的工作是小型的專案,精確數量的 PHP元件已足夠解決,那就使用元件。元件讓我們輕易地使用現存的工具,減少花費在工具上磨合的時間,並專心於手邊較大的任

Page 7: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 55

務。元件也讓我們的程式碼保持輕量以及靈活,我們只使用需要的程式碼,並在發現更

適合的元件時輕易替換現有的元件。

如果你的工作是大型的專案,有多個團隊成員並且受益於框架所提供的慣例、準則和架

構,那就使用框架。但是框架為我們做了許多決定,並且要求我們要遵循它的一套慣例,

框架缺乏彈性,但我們確實得到了一些創新的想法,是從組合一批 PHP元件中無法獲得的,如果這個權衡可以被接受,盡管使用框架來引導協助專案的開發。

尋找元件

你可以在 Packagist(https://packagist.org/,圖 4-1)中找到現代的 PHP元件,實際上它就是個 PHP元件目錄,這個網站聚集了 PHP元件並且可以使用關鍵字搜尋,最好的元件都在 Packagist中被條列出來,對於 Jordi Boggiano和 Igor Wiedler建立了如此珍貴的社群資源,我向他們表示敬意。

我常被問到哪個元件是我心中最佳的 PHP 元件,這是個很主觀的問題,但我大致

上認同列在 Awesome PHP(https://github.com/ziadoz/awesome-php)中的 PHP

元件,那是由 Jamie York(https://github.com/ziadoz)所策劃的 PHP 元件清單。

圖 4-1:Packagist 網站

Page 8: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

56 │ 第四章

商店

別把時間浪費在已經解決的問題上。你需要發送和接收 HTTP訊息?去 Packagist並搜尋 http,Guzzle會是第一個結果,請直接使用它;你需要剖析 CSV檔案?去 Packagist並搜尋 csv,挑一個 CSV元件並且使用它。將 Packagist想成是一家雜貨店,你可以在裡面挑選最適合的 PHP元件,Packagist大致上都會有足以解決你的問題的 PHP元件。

選擇

如果 Packagist上有多個 PHP元件都滿足你的需求呢?要如何挑選最適合的那個一個?Packagist保有每一個元件的統計數據,Packagist可以告訴你每一個 PHP元件被下載或被加上星號(圖 4-2)的次數,越多的下載數和星號數代表這個元件可能是個好選擇(並不是永遠如此),儘管如此,因為每天都會有很多新的元件加入,所以也別看低了下載

數少的新套件。

如果你的 Packagist關鍵字搜尋回傳了為數眾多的結果,將會難以找到完美的 PHP元件,你不能永遠依賴下載數統計,大眾的選擇不一定永遠都是正確的,當一個元件越來越熱

門,Packagist必須要依實記錄下來,但是有時這將成為一種問題,所以我建議你依賴口耳相傳和同好間的推薦,來確保自己選擇了正確的 PHP元件。

圖 4-2:Packagist 網站搜尋結果

Page 9: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 57

留下回饋

如果你找到了中意的 PHP元件,在 Packagist將這個元件加上星號並且以你的管道和其他 PHP開發者分享,包含 Twitter、Facebook、IRC、Slack和其他的管道。這將幫助最好的 PHP元件被其他開發者發現。

使用 PHP元件

Packagist是你可以找到 PHP元件的地方,而 Composer(https://getcomposer.org/)是你安裝 PHP元件的方法,Composer是 PHP元件的相依性管理者,在命令列環境下使用。你可以告訴 Composer你需要哪個 PHP元件,Composer會下載並且自動載入這個元件到你的專案中,就是這麼簡單。因為 Composer是相依性管理器,它也可以解析並且下載你元件的相依性套件(並且下載這些相依性的套件的相依性套件,如此循環下去)。

Composer和 Packagist也有緊密的互動關係,當你告訴 Composer想要使用 guzzlehttp/

guzzle元件,Composer擷取在 Packagist列表上的 guzzlehttp/guzzle元件,找到元件

的 repository URL,判斷是否為適當版本,並且尋找元件的相依性,最後 Composer下載 guzzlehttp/guzzle元件和它的相依性套件到你的專案中。

Composer十分重要,因為相依性管理和自動載入都是難以解決的問題,自動載入是個程序,可以在有需要時自動載入 PHP類別,省去使用 require()、require_once()、

include()或 include_once函式。舊版的 PHP讓我們可以用 \__autoload()函式撰寫自

製的自動載入器,當我們實例化一個未被載入的類別,這個函式會被 PHP直譯器自動呼叫,PHP接著採用了 SPL函式庫中更有彈性的 spl_autoload_register()函式,實際

上 PHP類別如何被自動載入將完全取決於開發者。不幸的是,缺乏共通的自動載入器標準導致每一個專案都使用不同的自動載入器實作方式,這將會導致開發者難以使用其

他開發者所提供的程式碼。

PHP Framework Interop Group認清到這個問題並且建立了 PSR-0標準(已被 PSR-4標準取代),PSR-0和 PSR-4標準建議了組織程式碼到名稱空間和檔案系統目錄的方式,讓程式碼可以兼容於一個標準的自動載入器實作方式,如同我在第三章中暗示的,我們

不必自己撰寫 PSR-4自動載入器,Composer相依性管理器會為所有的 PHP元件自動產生兼容於 PSR的自動載入器,Composer有效地為我們處理了相依性管理和自動載入的問題。

Page 10: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

58 │ 第四章

我相信 Composer 是 PHP 社群中最重要的產出,它改變了我建立 PHP 應用程式

的方式,我在每一個 PHP 專案都使用 Composer,因為它大幅的簡化了整合使用

第三方 PHP 元件的過程,如果你還未使用 Composer,那麼應該從現在開始研究

它。

安裝 Composer 的方法

Composer的安裝很簡單,開啟終端機並且執行下列指令:

這個指令以 curl下載 Composer下載器腳本,以 php執行下載器腳本並且在當前目錄建

立 composer.phar檔案,composer.phar檔案為 Composer執行檔。

絕不要執行從遠端 URL 下載下來的未知執行檔,確認你先檢查了遠端的程式碼檔

案並且確切知道它的用途,同時確認使用的是 HTTPS 來下載遠端程式碼。

我偏好使用以下指令將下載下來的 Composer執行檔移至 /usr/local/bin/composer:

確認你使用了以下指令讓 Composer執行檔可被執行:

最後,為了在 PATH環境變數中加上 /usr/local/bin目錄,在你的 ~/.bash_profile檔中加上下行:

你現在應該可以在終端機中輸入 composer,並看到 Composer選項列表(圖 4-3)。

Page 11: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 59

圖 4-3:Composer 指令列選項

使用 Composer 的方法

現在我們已經安裝了 Composer,試著下載一些 PHP元件吧。Composer原則上以每一個專案為基礎下載 PHP元件。

元件名稱

首先,你必須列出專案中所需要的元件,具體來說,列出每一個元件的服務提供者和套

件名稱。每個PHP元件都有服務提供者和套件名稱,舉例來說,league/flysystem(https://packagist.org/packages/league/flysystem)元件的服務提供者名稱是 league,套件名稱是 flysystem,服務提供者和套件名稱以 /字元做區隔,合在一起成為完整的元件名稱

league/flysystem。

服務提供者名稱有全域的唯一性,並且提供了一個全域的身分,封裝了套件的內容,套

件名稱可以用來辨認出指定服務提供者名稱中我們所需的套件,Composer和 Packagist使用 vendor/package命名規則來防止不同服務提供者的 PHP元件間名稱的衝突,你可以在每個元件的 Packagist目錄列表中找到該元件的服務提供者和套件名稱(圖 4-4)。

Page 12: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

60 │ 第四章

圖 4-4:Packagist 服務提供者和套件名稱

元件安裝

每個 PHP元件都可以有多個版本(例如 1.0.0、1.5.0或 2.15.0)開放使用,每個版本都會列在該元件的 Packagist目錄列表中。

語義版本(Semantic Versioning)

現代的 PHP 元件使用 Semantic Versioning scheme,包含三個編號,並以 .字元

區隔(例如 1.13.2)。第一個數字代表主要發行編號,一旦 PHP 元件的更新破壞

了跟從前版本的相容性,主要發行編號就會增加。第二個數字代表次要發行編號,

一旦 PHP 元件的更新兼容於從前版本,次要發行編號就會增加。第三個數字代表

補丁發行編號,一旦 PHP 元件修復版本相容性問題,補丁發行編號將會增加。

幸運的是,我們不用自己判斷每個元件的最穩定版本編號,Composer已經為我們做了這件事,在終端機中進入專案中最上層的目錄,並且為每個 PHP元件執行以下指令:

將 vendor/package替換成元件的服務提供者和套件名稱,舉例來說,如果要安裝

Flysystem元件,執行以下指令:

這個指令指示 Composer尋找並且安裝元件的最穩定版本,同時指定 Composer更新元件到最多(不包含)下一個主要版本,以前一個例子來說,在 2014年 10月以前安裝Flysystem的版本是 0.5.9並且會更新 Flysystem元件最多(不包含)到版本 1.*。

Page 13: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 61

你可以在專案最上層目錄裡新建立或更新的 composer. json 檔案中檢查這個指令的結果,這個指令同樣會建立一個 composer.lock 檔案,把這兩個檔案加入版本控制系統之中。

範例專案

為了更熟悉 Composer,我們將實際建立一個 PHP範例應用程式,這個應用程式將會從CSV檔案中掃描 URL並且回報所有可使用的 URL。我們會發送一個 HTTP請求到每個URL,如果 URL回傳的 HTTP回應狀態碼大於等於 400,我們將會發送一個可使用的

URL到標準輸出。我們的專案將是一個命令列應用程式,CSV檔案的路徑將是唯一的命令列參數,最後我們將執行腳本,傳入 CSV檔案路徑為參數,在標準輸出中查看可使用的 URL列表:

我們的專案目錄如同圖 4-5。

圖 4-5:元件目錄架構

當我開始一個新的 PHP專案時,第一件會做的事就是決定那些任務可以由現存的元件完成,scan.php腳本用來開啟並且迭代 CSV檔案,所以我們需要一個 PHP元件可以讀取並迭代 CSV資料;scan.php腳本也用來傳送 HTTP請求給 CSV檔案中每個 URL,所以我們需要一個 PHP元件用來傳送 HTTP請求和解析 HTTP回應,當然我們可以自己寫程式碼來迭代 CSV檔以及傳送 HTTP請求,但為何我們要把時間浪費在已解決的問題上?記得,我們的目標是掃描一列 URL,而非建立一個函式庫用來解析 HTTP和CSV。

Page 14: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

62 │ 第四章

瀏覽過 Packagist之後,我發現了 guzzlehttp/guzzle和 league/csv元件,前者處理

HTTP訊息,而後者解析並且迭代 CSV資料,讓我們在專案的最上層目錄中,以下列指令用 Composer安裝這兩個元件。

這些指令指示 Composer下載這兩個元件到專案最上層目錄中的 vendor/目錄,同時建立了 composer.json檔案和 composer.lock檔案。

composer.lock 檔案

利用 Composer安裝完專案相依性套件之後,你會發現 Composer建立了一個 composer.lock檔案,這個檔案列出專案中使用的所有 PHP元件以及版本編號(包含主要、次要和補丁編號),將我們的專案有效鎖定在特定的 PHP元件版本中。

為什麼這件事很重要?如果 composer.lock檔案存在,Composer在下載 composer.lock檔案中有條列的 PHP元件時,將依照 composer. lock檔案中列出的版本編號,而非Packagist中最新的版本。你應當版本控制 composer.lock檔案並且跟團隊成員分享,讓他們可以使用跟你相同的 PHP元件版本。如果你的團隊成員、臨時伺服器和產品伺服器都使用了相同版本的 PHP元件,則因元件版本相依性造成問題的風險將最小化。

composer.lock檔案的一個缺點是 composer install不會安裝比 composer.lock檔案所列出檔案版本更新的元件,如果你需要下載更新版本的元件並且更新你的 composer. lock檔案,使用 composer update,composer update 指令會更新你的元件到它們最新穩定版

本,並且同時更新 composer.lock檔案檔案到新的 PHP元件版本號碼。

自動載入 PHP 元件

現在我們利用 Composer安裝了專案的 PHP元件,那該如何使用它們?幸運的是,Composer下載PHP元件的同時,也為專案相依性套件建立了兼容於PSR的自動載入器,所以我們要做的就只是在 scan.php檔案的開頭 require Composer的自動載入器:

Composer的自動載入器只是一個 vendor/目錄中名為 autoload.php的 PHP檔案,當Composer下載每個 PHP元件時,Composer會解析每個元件自身的 composer.json檔,

Page 15: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 63

判斷這個元件要如何被自動載入,利用這些資訊建立一個兼容於 PSR的自動載入器。最後,我們可以在需要時實體化任何專案中的 PHP元件,並自動載入它們,非常簡潔有力不是嗎?

實作 scan.php

讓我們用 Guzzle和 SCV元件完成 scan.php腳本,記得,當我們的 PHP腳本執行時,CSV檔案的路徑是由第一個命令列參數所提供($argv陣列中取得),scan.php腳本如

同範例 4-1。

範例 4-1:URL掃描器應用程式

// 1.使用 Composer自動載入器

// 2.實例化 Guzzle HTTP客戶端

// 3.開啟並迭代 CSV

// 5.查看 HTTP回應的狀態碼

// 6.發送不良的 URLs到標準輸出

// 4.發送 HTTP OPTIONS請求

當我們實例化 guzzlehttp/guzzle 和 league/csv 元件時,注意我們如何使用

\League\Csv和 \GuzzleHttp名稱空間,我們怎麼知道要去使用這些特定的名稱空

間?我是藉由 guzzlehttp/guzzle和 league/csv 的文件中得知的,記得,良好的

PHP 元件都有文件。

加入數行 URL到 urls.csv檔案,一行一個 URL。確定至少有一個 URL是無效的,接著打開終端機並且執行 scan.php腳本:

Page 16: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

64 │ 第四章

我們執行了 php執行檔並且傳進兩個參數,第一個參數是 scan.php腳本的路徑,第二個參數是 CSV檔案的路徑,其中包含了 URL列表。如果有任何的 URL回傳了失敗的HTTP回應,將會在終端機畫面中顯示出來。

以 PHP 撰寫命令列腳本

你知道可以用 PHP 撰寫命令列腳本嗎?這是在網頁應用程式中,讓維護任務自動

化的好方式,下列網站可以讓你了解更多關於 PHP 指令列腳本:

y http://php.net/manual/wrappers.php.php

y http://php.net/manual/reserved.variable.argv.php

y http://php.net/manual/reserved.variable.argc.php

Composer 和私人 Repository

至今為止我都假設你使用的是公開的開源碼 PHP元件,但是隨著我使用開源碼軟體的經驗,我認知到僅僅使用開源 PHP元件不是永遠都符合所需,有時我們必須在同一個應用程式中混和開源的元件和自己發開的元件,對於某些公司來說尤其明顯,而因為

授權許可或安全因素導致他們無法開源內部開發的 PHP元件時,就成為了一個問題,Composer可以幫助我們解決這個問題。

Composer 同時也管理 repository 需要認證的私人 PHP 元件,當你執行 composer

install或 composer update指令時,如果元件的 repository需要認證,Composer將會要求你憑證安裝,Composer同時也會詢問是否要將此證明儲存到本地的 auth.json檔案(跟 composer.json檔案同目錄),一個 auth.json檔案的範例如下:

大部分的情況下,你不應該版本控制 auth.json檔案,而是讓專案開發者用自己的證明建立他們的 auth.json檔案。

Page 17: 序言 - 碁峰資訊epaper.gotop.com.tw/PDFSample/A434.pdf · PHP 應用程式,我們將跟Capistrano 一同研究PHP 應用程式的開發策略,我們會談到 測試的工具,例如PHPUnit

元件 │ 65

如果你不想要等 Composer主動詢問認證,可以使用以下指令在遠端機器中手動加入認證證明:

在這個範例中,http-basic是讓 Composer知道我們給定一個領域名稱作為認證的目標,example.org主機名稱指定了包含私有元件的遠端機器,最後的兩個參數是使用者名稱

和認證密碼,這個指令會將證明預設儲存到當前 auth.json檔案。

你也可以利用 --global來儲存全域性證明,這會讓 Composer在這個本地機器中的所有專案中都以此認證:

全域性證明儲存在 ~/.composer/auth.json檔案,如果使用Windows,全域性證明會儲存在 %APPDATA%/Composer之中。

在 Authentication management in Composer 了解更多關於 Composer 和私有

repository 的資訊(http://bit.ly/auth-manage)。

建立 PHP元件

此時你應當可以自己尋找並使用 PHP元件了,現在讓我們把重心轉移到製作 PHP元件,確切來說,我們將會把 URL掃描器應用程式轉換成 PHP元件並且將它提交到 Packagist元件目錄。

製作 PHP元件是個跟 PHP社群分享你個人成果的好方法,PHP社群建立於共享和互助的基礎之上。如果你在應用程式中使用開源碼元件,同樣可以回饋更多創新的開源碼元

件。

注意不要重複撰寫已經存在的元件,如果你改良現有的元件,考慮將你的改良以

pull request 的方式發送到原始元件,否則重複的元件會有混淆或是破壞 PHP 元

件生態系統的風險。