PHP擴展包的製作及對Laravel框架的集成

一、什麼是php擴展包?

我們用於項目增強有兩種方式:

  • PHP 原生擴展
    PHP 原生擴展(PHP Native Extension),我們通常指基於 C/C++ 語言開發的對 PHP 語言的擴展,需要編譯安裝,比如我們最常使用的 phpredis、GD、MySQL、cURL 擴展等,這裏有一個 PHP 的擴展列表

  • PHP 擴展包
    PHP 擴展包(PHP Package)或者 PHP 包,我們通常指用 PHP 代碼編寫的代碼包。它通常是一些特定功能的封裝,比如 Intervention/image,它是基於 PHP 圖像處理庫 GD/Imagick 實現的圖像處理功能包,具有非常強大且優雅的圖片處理 API,我們可以非常便捷的基於它完成常規的圖片操作,簡化開發工作。

本文要討論的就是 PHP 擴展包的開發,而不是 PHP 擴展。

二、Composer基礎介紹

在製作php擴展包之前,需要對php的包管理工具composer有一定了解。簡單來說,composer是php的包管理工具,可以類比於其他語言來理解它的作用:

語言 包管理工具
PHP composer
NodeJs npm
Java maven
Go govendor

1、基本組成

Composer 主要由三個部分組成:命令行工具、包倉庫、代碼庫
在這裏插入圖片描述

  • 包倉庫(Packagist)
    它是官方倉庫,也就是我們平常說的 Composer 源,它的作用是存儲這些包的信息,版本,代碼來源,依賴,作者,主頁等信息。官網是 packagist.org, 你也可以將自己的包發佈在上面,這樣 Composer 工具就能搜索與安裝你的包了。

  • 代碼倉庫(Repository)
    代碼倉庫,Packagist 支持公開與私有倉庫,通常是 GitHub 作爲代碼倉庫,當然也可以是 BitBucket 或者 GitLab。

  • 本地存儲路徑(Vendor directory)
    我們的 Composer 依賴包都統一安裝在項目的 vendor 目錄下,其中還有 vendor/composer 目錄用於存儲依賴包的一些基本信息,比如命名空間等。

2、命令行工具的基礎使用

我們安裝依賴的時候,composer 命令行工具會向包倉庫發起請求,請求需要安裝的包以及它依賴包的信息,它的依賴,版本等,然後在本地檢查依賴關係,檢查完畢後根據包信息裏的代碼庫地址(或者壓縮包地址)進行下載,下載到本地後安裝到 vendor 目錄。

Composer 命令在本文中不做贅述,相信大家都已熟練掌握,如有需要可查閱我的另一篇文章 Composer 基本命令介紹,更多指令可查閱 官方文檔

三、php擴展包的開發(composer包的製作)

此章節將以 laravel-onelogin 項目爲例穿插講解

1、基本目錄結構

寫代碼我們習慣按照一定的規律安排目錄結構,規範的目錄結構有助於我們擴展項目,也有助於他人閱讀。

比如我們按這種結構設計項目:

your-composer-package/
├── .editorconfig      # 編輯器配置文件,比如縮進大小、換行模式等
├── .gitattributes     # git 配置文件,可以設計導出時忽略文件等
├── .gitignore         # git 忽略文件配置列表
├── .php_cs            # PHP-CS-Fixer 配置文件
├── README.md    # 說明文檔
├── composer.json  # composer依賴文件
├── phpunit.xml.dist # 單元測試xml文件
├── src 						# 源代碼目錄
│   └── .gitkeep
└── tests					# 單元測試代碼目錄
    └── .gitkeep
  • src 目錄
    通常我們將源代碼放置到此目錄下,文件名與類命名遵循駝峯命名法,目錄與命名空間一致。

    注意:我們命名空間通常是按包名來的,然後 src 映射到駝峯寫法的命名空間,代碼組織結構請符合 PSR-4 規範

  • tests 目錄
    用於存放單元測試或者功能測試的測試用例代碼,與 src 組織規則基本一致。

  • .editorconfig 文件
    EditorConfig 的配置文件,EditorConfig 是一套用於統一代碼格式的解決方案,很多項目都有用到,比如 Laravel、jQuery、Underscore 和 Ruby 等等。

    EditorConfig 可以幫助開發者在不同的編輯器和 IDE 之間定義和維護一致的代碼風格。EditorConfig 包含一個用於定義代碼格式的文件和一批編輯器插件,這些插件可以讓編輯器讀取配置文件並依此格式化代碼。EditorConfig 的配置文件十分易讀,並且可以很好的在 VCS(Version Control System)下工作。

    簡單的說就是,這個配置文件定義了一些規則,比如 PHP 縮進是用空格還是用 Tab。它會被現代的編輯器所識別並應用(部分編輯器可能需要安裝對應的插件,請參考 EditorConfig 官網 )使用。

  • .gitattributes
    Git 的屬性配置文件,你可以對個別文件或目錄定義不同的合併策略,讓 Git 知道怎樣比較非文本文件,在你提交或簽出前讓 Git 過濾內容。你將在這部分瞭解到能在自己的項目中使用的屬性,以及一些實例。更多請參考:《自定義 Git - Git 屬性》- git-scm.com

  • .gitignore
    Git 忽略文件列表配置文件,將不需要納入版本控制的文件或者目錄按行配置在該文件即可。

  • .php_cs
    代碼格式修復工具 PHP-CS-Fixer 配置文件,它可以按配置的標準自動修復代碼格式,以及統一文件頭註釋等非常多的功能。

  • README.md
    項目說明文檔,一份項目介紹與使用指引,維護狀態授權方式等。

  • composer.json
    Composer 配置文件。

  • phpunit.xml.dist
    PHPUnit 配置文件,指定測試目錄與測試環境變量等,具體內容請參考官方文檔:《組織測試:用 XML 配置來編排測試套件》- P…

  • .gitkeep
    如果一個目錄爲空,我們是無法納入到版本控制中的,所以我們創建了一個隨意命名(最好還是按業界通用做法命名爲 .gitkeep)的隱藏文件來保證 目錄不爲空。

下面介紹幾種初始化composer包的方式:

  • composer init
    composer init 指令可以幫助我們初始化生成 composer.json 文件。

     $ composer init
    
    Welcome to the Composer config generator
      
    This command will guide you through creating your composer.json config.
    
    Package name (<vendor>/<name>) [wyq/test]:
    Description []: test
    Author [wyq <[email protected]>, n to skip]:
    Minimum Stability []:
    Package Type (e.g. library, project, metapackage, composer-plugin) []: library
    License []: mit
    
    Define your dependencies.
    
    Would you like to define your dependencies (require) interactively [yes]? yes
    Search for a package:
    Would you like to define your dev dependencies (require-dev) interactively [yes]? no
    
    {
        "name": "wyq/test",
        "description": "test",
        "type": "library",
        "license": "mit",
        "authors": [
            {
                "name": "wyq",
                "email": "[email protected]"
            }
        ],
        "require": {}
    }
    
    Do you confirm generation [yes]?
    

    指引流程完成後當前文件夾會增加 composer.json 文件。其他目錄結構或文件需要手動創建。

  • package-builder 工具
    我們在開發過程中每次都去建立這個目錄會比較麻煩,我們可以使用包結構生成工具來完成這些基礎工作:overtrue/package-builder

    安裝:

    composer global require "overtrue/package-builder" --prefer-source
    

    使用:

    package-builder build [目標目錄]
    
  • Bootpack 工具
    Bootpack 是 Laravel 5 包啓動器,它會生成更詳細的與Laravel結構相似的目錄結構:

    packages/LaravelNews
    └── example
        ├── composer.json
        ├── LICENSE
        ├── README.md
        └── src
            ├── Assets
            │   └── README.md
            ├── Classes
            │   ├── ExampleClass.php
            │   └── README.md
            ├── Commands
            │   ├── ExampleCommand.php
            │   └── README.md
            ├── Config
            │   └── example.php
            ├── Contracts
            │   ├── ExampleContract.php
            │   └── README.md
            ├── Controllers
            │   ├── ExampleController.php
            │   └── README.md
            ├── ExampleServiceProvider.php
            ├── Middleware
            │   ├── ExampleMiddleware.php
            │   └── README.md
            ├── Migrations
            │   ├── 2017_08_11_171401_create_Example_table.php
            │   └── README.md
            ├── Routes
            │   ├── api.php
            │   ├── README.md
            │   └── web.php
            ├── Translations
            │   ├── en
            │   │   └── basic.php
            │   └── README.md
            └── Views
                ├── README.md
                └── sample.blade.php
    

    在此不做過多介紹,可查閱 bootpack 倉庫 來獲取更多關於 Bootpack 的信息。

2、示例

簡單來說,我們只需要像平時封裝service類一樣,編寫代碼,將功能封裝起來即可。composer包實際上相當於提供了自動加載方便版本控制,結合代碼倉庫方便託管和共享,讓我們在不同項目中複用代碼時,不用再手動粘貼文件,讓我門的代碼能夠以更規範且方便的形式提供給他人使用。

【此章節主要以線下分享、演示爲主】

3、對 Laravel 框架的集成

在 Laravel 應用的 config/app.php 配置文件中,providers 選項定義了能夠被 Laravel 加載的服務提供者列表。當有人安裝你的擴展包時,你需要將你的服務提供者包含到這個列表中。你可以將服務提供者定義到擴展包的 composer.json 文件中的 extra 部分,而不是讓用戶手動將你的服務提供者添加到列表中

"extra": {
        "laravel": {
            "providers": [
                "Wyq\\Onelogin\\Providers\\OneLoginServiceProvider"
            ]
        }
    }

擴展閱讀:Laravel 自動發現擴展包是怎樣實現的

服務提供者負責將一些東西綁定到 Laravel 的 服務容器 中,並且告訴 Laravel 從哪裏加載擴展包的資源文件,例如路由、配置文件、視圖、語言包等。

wyq/laravel-onelogin 包爲例,我們在composer的extra項中設置了 OneLoginServiceProvider 服務提供者,讓他在自動加載時被發現,之後被框架註冊並執行。在 register 方法中,我們讓默認配置被加載到框架中。在 boot 方法中,我們讓路由自動註冊到框架中,並且提供了配置發佈功能:

class OneLoginServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
    	// 讓i1默認配置合併到框架中
    	$this->mergeConfigFrom(
            __DIR__.'/../config/i1.php', 'i1'
        );
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //自動註冊路由
        $this->loadRoutesFrom(__DIR__.'/../routes.php');

        //發佈配置
        $this->publishes([
            __DIR__.'/../config/i1.php' => config_path('i1.php'),
        ], 'config');
    }
}

上邊的示例只用到了 config、route 資源的註冊,此外還提供了數據庫遷移、語言包、視圖、命令、公共資源文件、發佈羣組文件等,他們的使用方式都是相似的,都十分簡單。
更多關於laravel提供的資源文件註冊方式,可以查閱官方文檔:擴展包開發

四、包倉庫介紹及私有倉庫搭建

當我們PHP擴展包完成後,就可以嘗試發佈上線,在其他項目中使用它。

你可以選擇上傳到github,或者其他git倉庫託管平臺,如gitee、coding、gitlab等。但是值得注意的是:composer官方倉庫 Packagist 是以github作爲代碼倉庫的。也就是說,如果你選擇github託管代碼,可以很方便創建composer倉庫。一般情況下,開源項目我們強烈推薦選擇github,配合Packagist發佈自己的擴展包,但如果不希望代碼外泄,則需要使用私有git倉庫,或者自建composer倉庫,然後通過配置repository來獲取你的私有擴展包。

首先,我們來介紹一般場景下開源項目擴展包的發佈流程:

  1. 創建github代碼倉庫
    此步驟不做描述

  2. 提交到 Packagist
    Composer 安裝包都是從 Packagist 源讀取信息的,所以我們需要去註冊我們的擴展包,別人才能安裝,如果你還沒有 Packagist 賬號,先註冊一個,建議使用 GitHub 登錄:
    在這裏插入圖片描述
    登錄以後,點擊頂部菜單欄 “Submit” 開始提交項目,填入我們 代碼所在的 GitHub 的倉庫 URL,然後點 “Check”,然後提交即可:
    在這裏插入圖片描述

    新版 GitHub 已經不需要手動註冊 webhook 了,當然前提是你在 packgist.org 使用github賬號登錄授權。
    //@TODO 由於寫此文時主要是私有包倉庫建設,所以關於github的部分沒有實際驗證,如有問題後續會補充。

  3. 在項目中使用

    在packgist.org發佈後,直接在項目中require即可:

    composer require wyq/laravel-onelogin
    

如果我們不想讓所有人都能使用我們的擴展包,則需要使用私有倉庫,讓擁有私有倉庫訪問權限的人才能正常獲取擴展包:

  1. 創建私有git倉庫
    此過程不做描述

  2. 對composer.json文件增加repository

    	"repositories": [
            {
                "type": "vcs",
                "url": "[email protected]:wyq/laravel-onelogin.git"
            }
        ]
    

    其中 repositories 可以是數組,也可以命名個key,如下:

    "repositories": {
        "laravel-onelogin": {
            "type": "vcs",
            "url": "[email protected]:wyq/laravel-onelogin.git"
        }
    }
    

    需要注意的是,repository 支持多種 type 類型,上文使用的 vcs 即 version control system,下文會介紹另一種type:composer 類型,完整信息可見官方文檔 Repositores 部分

  3. 在項目中使用
    當我們添加了新的repository之後,composer在官方倉庫找不到對應的擴展包時,會繼續依次使用配置的源來尋找擴展包,因此我們依然是直接執行 require 指令即可:

    composer require wyq/laravel-onelogin
    

私有包倉庫搭建

上邊我們介紹了私有擴展包如何使用,但是我們使用vcs倉庫時會面臨一個問題:每增加一個擴展包,就要增加一條repositries的倉庫。

這時,我們可以通過搭建包倉庫來管理擴展包。這裏我們可以選擇satis或toran他們都是官方提供。

satis

Satis 是開源的,它只是一個靜態的 Composer 儲存庫生成器。它有點類似於一個超輕量的 packagist , 可以用於託管公司的私有 packages 或者 保存自己的私有 packages 。可以從 GitHub 下載 或者 在命令行運行以下命令:

php composer.phar create-project composer/satis --stability=dev --keep-vcs

創建完成後,如果目錄中沒有satis.json文件,則需要手動創建:

{
  "name": "huanqiu/repository",
  "homepage": "http://repository.demo.com",
  "repositories": [
    {
        "type": "vcs",
        "url": "[email protected]/wyq/laravel-onelogin.git"
    }
  ],
  "require": {
      "wyq/laravel-onelogin": "*"
  }
}

更完整的配置示例:

{
  "name": "Easy Repository",
  "homepage": "http://packagist.satis.cc",
  "repositories": [
    {"type": "vcs","url": "https://gitlab.local.com/aBigPackage/helloWorld"},
    {"type": "composer", "url": "https://packagist.laravel-china.org"}
  ],
  "archive": {
    "directory": "dist",
    "format": "tar",
    "skip-dev": true,
    "prefix-url": "http://packagist.satis.cc"
  },
  "abandoned":{
    "lastcraft/simpletest" : "simpletest/simpletest"
  },
  "require":{
    "monolog/monolog": "*",
    "darkaonline/l5-swagger": "~5.4",
    "laravel/laravel":"~5.4",
    "league/flysystem-aws-s3-v3":"*",
    "zircote/swagger-php":"*",
    "simpletest/simpletest":"*"
  },
  "require-all": false,
  "require-dependencies": true,
  "require-dev-dependencies": true
}

配置解釋:

// Composer 私有源的名稱,可隨意
"name": "Easy Repository",

// 建立之後home頁面的地址(用於查看這個源有哪些package)
"homepage": "http://packagist.satis.cc",

// 獲取package的地址
/** 
  這裏如果你是需要從私有的git源獲取package的話,就參照如下這樣寫就可以了
  (帶.git和不帶.git似乎都ok)
  {"type": "vcs","url": "https://gitlab.local.com/aBigPackage/helloWorld"}

  如果你是需要構建內網的源,且內外網分離的情況下從外網獲取package到內網,就參照下面這樣寫就好了
  (沒有必要挨個去寫需要引用的package的github地址)
  {"type": "composer", "url": "https://packagist.laravel-china.org"}
*/
"repositories": [
  {"type": "vcs","url": "https://gitlab.local.com/aBigPackage/helloWorld"},
  {"type": "composer", "url": "https://packagist.laravel-china.org"}
],

//如果需要satis將package下載到本地,直接從本地拉取,則需要配置這一項
//(內網源必須配置此項)
"archive": {
  "directory": "dist",

  //tar or zip
  "format": "tar",

  //是否需要爲分支創建下載(默認只對有tag的提交創建下載)
  "skip-dev": false,
  "prefix-url": "http://packagist.satis.cc"
},

// 被拋棄或替換的package
"abandoned":{
  //true表示這個 package 真正的被拋棄
  "lox/simpletest":true
  //表示 lastcraft/simpletest 被 simpletest/simpletest 替換
  "lastcraft/simpletest" : "simpletest/simpletest"
},

// 需要 satis 的全部的 package
"require":{
  "monolog/monolog": "*",
  "darkaonline/l5-swagger": "~5.4",
  "laravel/laravel":"~5.4",
  "league/flysystem-aws-s3-v3":"*",
  "zircote/swagger-php":"*",
  "simpletest/simpletest":"*"
},

//是否需要將配置的源的全部的package都拉取
"require-all": false,
//是否自動解決依賴
"require-dependencies": true
//是否自動解決dev依賴
"require-dev-dependencies": true

倉庫構建:

// 全部需要的package重新檢查更新並構建
// 強烈推薦追加 --skip-errors 參數,否則碰到某些已經被放棄的 package 會卡住構建
php bin/satis build satis.json public/ --skip-errors

// 僅僅重新檢查更新並構建指定的幾個包
php bin/satis build satis.json public/ A/package B/other-package

// 如果只想掃描單個存儲庫並更新其中找到的所有包,請將VCS存儲庫URL作爲可選參數傳遞:
php bin/satis build --repository-url https://only.my/repo.git satis.json public/

當構建完成後,public目錄下會生成package.json文件,記錄所有擴展包的索引;include文件夾存儲壓縮包(如果設置了archive)

toran

Toran-Proxy是一套相對完整的私有倉庫管理和代理工具( https://toranproxy.com/ ),也是composer作者開發的,可靠性也有保證。相比Satis而言主要有以下幾個優勢:

  • 提供了一套簡單的UI來管理包,可以直接通過表單提交和更新;
  • 提供了一套簡單的API,可以被作爲持續集成的一部分,觸發添加、更新包等操作;
  • 除了私有包管理外,還提供了官方packagist或其他代理源的內部代理功能,提升加載速度的同時,當packagist或其他代理源不能工作時,一定程度上保障服務可用性

關於toran的內容在此不做詳細介紹。

私有包倉庫使用

向 composer.json 文件的 repositories 增加新的倉庫源即可。

"repositories": [
        {
            "type": "composer",
            "url": "https://repository.demo.com/composer"
        }
    ]

參考文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章