composer的原理和使用(上)--phar的相關

簡書markdown不支持目錄.png

什么是composer

在之前的PHP開發中,我也僅僅是使用composer來進行依賴的管理,沒有深度去理解到底什么是composer,今天有時間就開始深入的研究一下。

Composer 不是一個包管理器。是的,它涉及 "packages" 和 "libraries",但它在每個項目的基礎上進行管理,在你項目的某個目錄中(例如 vendor)進行安裝。默認情況下它不會在全局安裝任何東西。因此,這僅僅是一個依賴管理。 --來自composer的官方文檔

其實上面的文案在一開始接觸composer的時候我是能明白他說什么的,但是今天仔細分析又發現對其中的很多表述還是比較模糊。首先是包管理器的理解。

包管理器又稱軟件包管理系統,它是在電腦中自動安裝、配制、卸載和升級軟件包的工具組合,在各種系統軟件和應用軟件的安裝管理中均有廣泛應用。 --百度百科

軟件包(SoftWare Package)是指具有特定的功能,用來完成特定任務的一個程序或一組程序。可分為應用軟件包和系統軟件包兩大類。應用軟件包與特定的應用領域有關,又可分為通用包及專用包兩類。通用軟件包根據社會的一些共同需求開發,專用軟件包則是生產者根據用戶的具體需求定制的,可以為適合其特殊需要進行修改或變更

通過軟件包管理器能理解,包管理器更多的管理的能直接執行的應用程序,像rpm,apt,brew,yum都是指定的類Unix系統的包管理器。而對于PHP腳本語言,在開發者編寫的腳本 一般依賴的是各種庫的腳本。所以在composer定義中先說明composer不是一個包管理器。

終于后面它涉及 "packages" 和 "libraries" ,我一直想接著查詢 "packages" 和 "libraries"區別,但是沒有找到相關描述。但是定義最后一句明確說明了,他是一個依賴管理工具。

phar 文件

在我們下載composer的時候都可以看到是下載一個composer.phar 文件。那么phar 文件是什么類型的文件,他和PHP的關系是什么?所以要深入了解composer應該先從phar開始

phar打包PHP程序

PHAR (“Php ARchive”) 是PHP里類似于JAR的一種打包文件。如果你使用的是 PHP 5.3 或更高版本,那么Phar后綴文件是默認開啟支持的,你不需要任何其他的安裝就可以使用它。phar歸檔文件有三種格式:tar歸檔、zip歸檔、phar歸檔,前兩種執行需要php安裝Phar 擴展支持,用的也比較少,這里主要講phar歸檔格式。

  • 我們為什么需要phar呢,是因為PHP的腳本語言的特性,如果你開發的一個項目擔心在部署的時候被修改,那么可以通過將項目中的多個文件打包成一個文件,并且這個文件默認是只讀的方式。這樣就可以封裝上線了。
  • 簡單的理解一下:項目文件的打包可以通過zip,tar,只不過phar打包后的文件不需要顯示的再解壓,可以直接被PHP使用。

Rather than using the ZIP file format the simpler tar format was used, and the first PHAR was created using the tar command line utility[1] as a proof of concept. On June 14, 2004[2] the initial PHP_Archive package was proposed to PEAR and on December 13, 2004 it was accepted unanimously.[3] 來自 wiki百科
可以看到第一個phar就是tar格式打包的文件,而且是直接用tar命令行工具生成。

phar 文件是文本文件還是二進制

通過上文的理解,既然我們將項目文件整合到一個文件了,所以理所當然的就會考慮重寫整理文件格式以達到節省空間提高效率的目的。所以打包后的phar是一個二進制文件(想想第一個tar打包的phar文件)。 只不過隨后phar開始自己的打包的文件格式。下圖是phar打包文件格式

phar manifest format.png

phar 文件是支持權限和分組的。

The Phar manifest is a highly optimized format that allows per-file specification of file compression, file permissions, and even user-defined meta-data such as file user or group. All values greater than 1 byte are stored in little-endian byte order, with the exception of the API version, which for historical reasons is stored as 3 nibbles in big-endian order.

phar 日常使用例子

新建項目目錄如下

myapp.png

其中的 build 目錄里將放置 PHAR 文件,這樣能避免它跟源碼程序混合到一起。src 放的就是我們的PHP源碼。

index.php 會成為我們的應用的入口程序,common.php 可以放置應用需要的一些共有代碼,config.ini 是我們的配置文件。

index.php 大概是這樣樣子:

<?php
require_once "phar://myapp.phar/common.php";
$config = parse_ini_file("config.ini");
AppManager::run($config);

common.php 大概是這樣的:

<?php
class AppManager
{
    public static function run($config) {
         echo "Application is now running with the following configuration... ";
         var_dump($config);
     }
}

在我們的PHP應用目錄里,需要有一個創建Phar文件的腳本,我們給它起名叫 create-phar.php,放置到 myapp 的跟目錄下,里面添加如下代碼:



<?php

/**
 * 目的 :將PHP框架項目,打包成一個 .phar 文件
 * 常用 :這個打包,一般是用PHP語言來做 linux 系統軟件的,如composer.phar
 *
 * 
 * 方法:
 * 
 * 壓縮myaoo 目錄下的(php,可選)文件
 *
 * 1、將 php.ini 的 `;phar.readonly = On` 改為 `phar.readonly = Off`
 *
 * 2、運行 create-phar.php(本文件),會在當前目錄下生成 myapp.phar
 *
 * 3、在git-bash里,運行 php ./myapp.phar
 *
 * 4、在git-bash里(網頁也可以),運行php ./myapp/index.php。輸出結果  等同于 第3步輸出結果
 */


## 壓縮的包名
$phar = new Phar($buildRoot . "/myapp.phar", 
        FilesystemIterator::CURRENT_AS_FILEINFO |
        FilesystemIterator::KEY_AS_FILENAME, "myapp.phar");
// 可以簡寫 $phar = new Phar('myphar.phar');

## 壓縮的路徑 【可選參數,壓縮文件類型】
/*
$phar["index.php"] = file_get_contents($srcRoot . "/index.php");
$phar["common.php"] = file_get_contents($srcRoot . "/common.php");
*/

$phar->buildFromDirectory(__DIR__ . '/myphar', '/\.php$/');


## 壓縮方式,這里用 gzip 方式
$phar->compressFiles(Phar::GZ);

$phar->stopBuffering();

## 默認自動加載 test_phar 目錄下的哪個文件。|  等同于 nginx 配置 sever {listen 80; …… index index.php; }
$phar->setStub($phar->createDefaultStub('index.php'));

一個新 Phar 對象的創建通常需要三個參數。第一個參數是Phar文件的路徑。你不僅可以通過它創建Phar文件,還可以對現存的Phar文件進行操作。

第二個參數是設定 Phar 對象如何處理文件。Phar 對象繼承了 PHP RecursiveDirectoryIterator 對象,這個參數是直接傳遞到父類里。這里提供的值是RecursiveDirectoryIterator 的缺省值,能滿足目前的要求。

第三個參數是Phar文件的別名,在內部引用這個Phar文件時都要使用這個別名。也就是說,Phar內部文件的相互include都需要顯式的使用這個別名。例如,之前的index.php 對 common.php 的引用就是這種方式。

在Phar對象創建之后, index.php 和 common.php 就被加入了Phar文件里了。Phar 對象是一個數組,file_get_contents() 方法將各個文件的內容讀到數組里。你可以向里面添加很多的文件,但如果你考慮添加大量的文件,比如說整個目錄下的文件,你可以考慮使用更方便的 buildFromDirectory() 方法。

打開命令行窗口,切換到 myapp 目錄下,運行命令:

aabouzekry@platinum:~/myapp$ php create-phar.php

我們可以直接訪問Phar打包的應用,但這需要額外配置web server來將Phar文件發送給正確PHP解析器。另外一個辦法是創建一個run腳本,include 這個Phar文件
在web server的根目錄創建一個叫 run.php 的PHP腳本:

<?php
require "myapp.phar";

這段代碼的作用就是可以讓你免去了去配置web server來直接解析Phar文件。如果你的應用使用的是一個共享的虛擬主機,沒有權限來配置web server,那么,這種方式是一個完美的解決方案。

創建了run.php后,我們的web server的根目錄會變成這樣:


run.png

為什么composer命令可以不依賴類php命令而直接運行

如果composer.phar是一個包,那么正常使用composer應該全部是php composer.phar ** 這樣的形式,為什么我們在日常使用中缺可以

comoser install

這樣的形式來使用呢?
想弄明白為什么,我們先從composer的安裝開始過程開始研究

curl -sS https://getcomposer.org/installer | php

從命令上我們可以看書,這個安裝命令其實就是從網上下載了installer的PHP文件,然后在本地執行。這個執行過程就類似于上面的打包phar包。最終生成了composer.phar 文件。

  • linux系統中 全局安裝,其原理就是: linux系統中文件后綴名并不代表可執行類型,所以將composer.phar移動到bin目錄后修改文件名就可以
mv composer.phar /usr/local/bin/composer
  • windows系統中composer setup.exe 通過bat文件來實現調用composer.phar bat文件類似于
@echo off 
php53\php %D:\phpStudy\tools\composer.phar %*

在這里有個疑問,就是為什么linux的composer.phar文件就可以直接執行,難道comopser.phar是一個可執行的二進制文件不需要PHP解釋器嗎? 這個問題思考了許久,后來從網上偶然看到一些人在解壓縮phar文件,所以我嘗試用文本編輯工具打開composer.phar ,就找到了答案

composer.phar.png

原來在在composer.phar的文件頭部,內嵌了一段shell代碼。至此了解了composer的運行前的必要知識。

如果想了解composer的運行原理,建議可以通過閱讀composer來了解
composer

后面一篇再開始講講怎么使用composer!

【參考資料】

http://php.net/manual/en/book.phar.php phar 官方文檔
https://en.wikipedia.org/wiki/PHAR_(file_format) phar wiki
http://www.webhek.com/post/packaging-your-php-apps-with-phar.html PHP開發常識:什么是Phar?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 是什么 如果你知道yum、apt-get、npm、bower等命令中的一種或者多種,那么,你也能很快知道compo...
    旱魃一樣閱讀 3,166評論 0 9
  • Awesome PHP 一個PHP資源列表,內容包括:庫、框架、模板、安全、代碼分析、日志、第三方庫、配置工具、W...
    guanguans閱讀 5,861評論 0 47
  • Composer Repositories Composer源 Firegento - Magento模塊Comp...
    零一間閱讀 3,970評論 1 66
  • 1、錄課一節~《西游記》導讀課,聽課兩節~《傅雷家書》和《海底兩萬里》導讀課。 2、最后一節課幫杜老師監考,閱讀課...
    潔言潔語閱讀 273評論 0 1
  • 從天而降和發自內心的雪花 都是你的預謀 那些被遺忘的溝壑 那些結痂的傷口 會一一填平 靈魂空曠,世界澄明 唯有不愿...
    上善若水_cd86閱讀 917評論 61 104