Composer入門

Java有Maven, Node.js有npm, ROR有gem, 這些語言的程序員在開心地使用包管理工具加速開發效率時,PHPer們還在複製粘貼的黑暗中。PHP在Composer以前,包管理的歷史不堪回首。php

在至關長的一段時間內,若是應用依賴於第三方庫,PHPer須要拷貝這些庫的源代碼, 或者經過PEAR、PECL安裝。若是第三方庫又依賴於更多的第三方庫,那麼很快就會進入依賴的黑洞。直到Composer出現,PHPer們看到了屬於PHP的包管理的曙光。git

注:Composer更新很慢,很難成功的,請看另外一篇博文 >>Composer更新慢的解決方案<<程序員

下面將以建立一個電商網站爲例,介紹Composer的使用方法。github

配置文件

在咱們開始一個項目的時候,首先會給項目取一個名字,咱們暫且叫絲綢之路吧,代號silk。首先要寫一個Composer的配置文件,來描述項目,爲此,在項目的根目錄下,創建文件名爲composer.json的配置文件。內容以下:web

<!-- lang: js -->
{
"name":             "meta/silk",
"description":      "another e-commerce website",
"keywords":         ["silk", "online shop", "good"],
"homepage":         "http://www.xxx.com ",
"time":             "2014-12-30",
"license":          "MIT",
"authors": [
    {
        "name":         "Elvis Lim",
        "email":        "elvis@xxx.com",
        "homepage":     "http://www.xxx.com",
        "role":         "Engineer"
    }
]}

若是您熟悉JSON格式,那麼上面這段內容不言而喻。事實上,這些鍵值對都是可選的。也就是說,能夠都不寫。可是若是要把項目打包成公共包發佈,那麼這些仍是須要寫上的,給你的包取個名字總不爲過。讓咱們來過一下這些鍵值對的意義吧。面試

<!-- lang: js -->
"name":             "meta/silk",

name, 表示包的名稱。若是你常常在Github上混,那這個值的表達方式必定很是熟悉啦。解釋下,一般包名包含兩部分,而且以 / 分隔。斜杆前面部分,表明包的全部者。目前大部分的包做者都喜歡用Github的用戶名做爲這部分的值。斜杆後面部分表明包的名稱。儘可能保持簡單和有意義些,便於記憶和傳播。大部分狀況下,不少人會用Github的代碼庫名稱來命名,固然,這種狀況下,代碼要存在Github比較有意義。shell

<!-- lang: js -->
"description":      "another e-commerce website",

應用簡介,這部分儘可能簡潔介紹下項目,別長篇大論。若是確實有不少話要說,那麼能夠寫在README.md文件裏。npm

<!-- lang: js -->
"keywords":         ["silk", "online shop", "good"],

關鍵詞的值是一個字符串數組,在發佈成公用庫的是時候,做爲元數據信息,有利於包的搜索和發現。json

<!-- lang: js -->
"homepage":         "http://www.xxx.com ",

主頁,能夠放你想放的任何頁面地址。swift

<!-- lang: js -->
"license": "MIT",

若是你決定將包公開發布,那麼記得選擇一個合適的許可證。這樣別的程序員在引用包的時候,經過查看許可證,確保沒有法律上的問題。

<!-- lang: js -->
 "authors":[{}]

做者字段能夠包含一個對象數組,也就是說能夠提供多個做者信息。

目前爲止,都是關於包自己的信息描述。做爲一個電商網站,可以發送電子郵件、導出訂單到Excel表是基本需求,這個時候天然想到了使用現有的庫來實現這些功能。要獲取這些庫,最簡單的方式是,搜索下這些庫,找到下載地址,下載個zip包,而後解壓到相應目錄下,根據文檔引入相應的文件。使用Composer,能夠更加自動和優雅地完成這個過程,這就是Composer的依賴管理。

依賴管理

在composer.json文件裏增長一個新的字段:require。這個字段的值是一個對象,一樣以鍵值對的形式構成。以上述提到的兩個依賴位置,寫成composer管理的方式以下:

<!-- lang: js -->
「require」: {
"swiftmailer/swiftmailer": 5.3.*[@dev](https://my.oschina.net/Thinker277),
"phpoffice/phpexcel": "dev-master"
}

以swiftmailer爲例,swiftmailer/swiftmailer 表明的是包名稱,5.3.*@dev, 是版本信息。合起來的意思就是說,咱們將要開發的應用,依賴於swiftmailer的5.3.*版本。其中:

5.3.*表示,可使用5.3.1版本,也可使用5.3.2版本,composer在獲取的時候,將尋找5.3版本下最新的版本。版本號支持一些更加寬泛的約束,好比>=1.0, >=1.0, <2.0,更加具體的信息能夠查看:http://docs.phpcomposer.com/01-basic-usage.md#The-require-Key

@dev表示能夠獲取開發版本。一般,開發版本意味非穩定版本,極可能存在bug。穩定性標籤能夠做用於特定的依賴項,也能夠做用於全局。

做用特定依賴項:默認狀況下,composer只會獲取穩定版本,若是這個例子咱們不加@dev約束,而5.3.*版本都是開發版本,那麼在獲取的時候composer就會報錯,指出改版本不符合要求。若是肯定這個開發版本沒有問題,那麼就能夠經過加@dev,讓Composer獲取這個開發版本。

全局穩定性設置:經過設置minimum-stability的值,來告訴Composer當前開發的項目的依賴要求的包的全局穩定性級別,它的值包括:dev、alpha、beta、RC、stable,stable是默認值。

至此,兩個依賴添加完畢,咱們能夠運行下Composer包更新命令,看看效果啦。

<!-- lang: shell -->
composer install

成功運行完畢,會在根目錄下發現vendor文件夾,裏面包含了剛剛咱們列出來的兩個包文件代碼。

require-dev

有時候,咱們會發現,有些包依賴只會在開發過程當中使用,正式發佈的程序不須要這些包,這個時候,就須要用到另一個鍵,即require-dev。例如,咱們想用codeception進行單元測試,那麼就能夠經過require-dev引入這個開發環境下的依賴包:

<!-- lang: js -->
「require-dev」: {
"codeception/codeception": "2.0.0 "
}

加了這個依賴後,再運行下命令看看效果。

<!-- lang: shell -->
composer install

自動加載

自此,composer已經幫咱們把須要的庫文件下載下來啦,接下去想到的就是如何引用這些庫文件。最簡單的方式就是require或者include,但這就不夠高大上了啊,須要花時間去庫文件裏查看須要引入哪些文件,費事並且容易出錯。好在composer能夠幫咱們解決這個問題。那就是autoload。

在運行完composer install命令後,怎麼調用PHPExcel庫呢?很簡單,只要引入vendor目錄下的autoload.php文件就能夠了。能夠在根目錄下,建一個index.php文件,加入一下內容:

<!-- lang: php -->
include 「vendor/autoload.php」
$excel = new PHPExcel();
var_dump($excel);

用瀏覽器訪問一下這個頁面,就會發現PHPExcel對象已經被成功建立啦,是否是很方便?

其實到目前爲止,咱們並沒用在composer.json文件里加入autoload字段,那麼何時須要加入呢? 那就是當咱們想讓composer幫咱們自動加載咱們本身定義的類的時候。例如,咱們本身寫了個訂單管理類,取名OrderManager,放在lib目錄下的OrderManager.php文件裏。內容以下:

<!-- lang: php -->
class OrderManager
{
    public function test()
    {
        echo "hello";
    }
}

那麼如何讓composer幫咱們自動加載這個類呢? 在composer.json里加入下面的內容:

<!-- lang: js -->
「autoload」:{
    "files":["lib/OrderManager.php"]
}

files鍵對應的值是一個數組,數組元素是文件的路徑,路徑是相對於應用的根目錄。加上上述內容後,運行命令:

<!-- lang: js -->
composer dump-autoload

讓composer重建自動加載的信息,完成以後,就能夠在index.php裏調用OrderManager類啦。

經過文件引入的方法雖然直觀,可是很費勁,每一個文件都得引入一次,實在不是好的解決辦法。有沒有更好的辦法呢?嘗試將autoload的值改爲:

<!-- lang: js -->
 "classmap":["lib"]

再此運行composer dump-autoload,嘗試調用,依然可以成功建立OrderManager類。其實,classmap經過創建類到文件的對應關係,當程序須要OrderManager類時,compoer的自動加載類經過查找OrderManager類所在的文件,而後再將改文件include進來。所以,這又致使了一個問題,那就是每加一個新類,就須要運行一次composer dump-autoload來建立類到文件到對應關係,比files方法雖然好一點,可是仍是很不夠舒爽啊!因而,PSR-0出場了。先了解下什麼是PSR-0。

FIG組織制定的一組PHP相關規範,簡稱PSR,其中

PSR-0自動加載 PSR-1基本代碼規範 PSR-2代碼樣式 PSR-3日誌接口 PSR-4 自動加載

目前就這五個規範,乍一看,PSR-0和PSR-4是重複了,實際上,在功能上確實有所重複。區別在於PSR-4的規範比較乾淨,去除了兼容PHP 5.3之前版本的內容,有一點PSR-0升級版的感受。固然,PSR-4也不是要徹底替代PSR-0,而是在必要的時候補充PSR-0——固然,若是你願意,PSR-4也能夠替代PSR-0。PSR-4能夠和包括PSR-0在內的其餘自動加載機制共同使用。

PSR-0規範的具體內容見:https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-0.md PSR-4規範的具體內容見:https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md

簡而言之,就是但願經過一組約定的目錄,文件名,類名定義方式,來實現快速經過類查找到文件,而後包含進來,實現自動加載。 PSR-4和PSR-0最大的區別是對下劃線(underscore)的定義不一樣。PSR-4中,在類名中使用下劃線沒有任何特殊含義。而PSR-0則規定類名中的下劃線_會被轉化成目錄分隔符。

不論是PSR-0仍是PSR-4,都要求有個命名空間,因此咱們須要對OrderManager類進行一些小的修改,加上命名空間:

<!-- lang: php -->
namespace SilkLib;
class OrderManager
{
    public function test()
    {
        echo "hello";
    }
 }

同時,文件夾的結構也要修改爲:應用根目錄\lib\SilkLib\OrderManager.php

而後修改composer.json裏的autoload部分以下:

<!-- lang: js -->
"autoload":{
    "psr-0":{
        "SilkLib":"lib/"
    }
}

這裏須要注意的是,SlikLib是命名空間,lib是目錄名,他們的組合告訴composer,文件搜索是在:lib/SilkLib/ 目錄下,而不是在 SilkLib/lib 目錄下,這一點要特別注意,有點繞,容易弄錯。

若是咱們把命名空間改爲 Slik\lib, 相應的目錄結構要改爲:應用根目錄\lib\Silk\lib\OrderManager.php,autoload部分的寫法相應的也要改爲:

<!-- lang: js -->
"autoload":{
    "psr-0":{
        "Silk\\lib":"lib/"
    }
}

注意Silk\lib是雙斜杆。好了,那咱們試試再加一個類,而後不用運行composer dump-autoload命令,看看新類是否能加載上。在lib目錄下,新增一個ShipManager.php文件,內容以下:

<!-- lang: php -->
namespace Silk\lib;
class ShipManager
{
    public function test()
    {
        echo 'hello ship class';
    }
}

嘗試在index.php文件中調用:

<!-- lang: php -->
$orderMgr = new Silk\lib\OrderManager();
$orderMgr->test();
$shipMgr = new Silk\lib\ShipManager();
$shipMgr->test();

運行成功,說明使用psr-0規範進行自動加載,比classmap更加方便。下面試試psr-4方式,整理下目錄結構,改爲:應用根目錄\lib\OrderManager.php,修改命名空間爲Silk, 修改autoload部分爲:

<!-- lang: php -->
"autoload":{
    "psr-4":{
        "Silk":"lib"
    }
}

嘗試調用,發現報錯Fatal error: Uncaught exception 'InvalidArgumentException' with message 'A non-empty PSR-4 prefix must end with a namespace separator. 提示要加上分隔符,那就加上吧:

<!-- lang: js -->
"autoload":{
    "psr-4":{
        "Silk\\":"lib"
    }
}

再次composer dump-autoload,運行測試,OK經過!

掌握require和autoload部分,其實就算Compoer入門啦,在詳細的內容,能夠經過查看composer文檔來了解。Happy Coding!

相關文章
相關標籤/搜索