王宁凯的个人博客

composer 简介

2019.10.16

介绍

Composer 是一个用于 PHP 依赖管理的工具。它实现了让你声明项目所依赖的库,并帮你完成安装 / 更新过程。

Composer 是类似 node's npm 和 ruby's bundler 的工具。

Composer 主要解决以下问题:

  1. 你有一个项目依赖于若干个库。

  2. 其中一些库依赖于其他库。

  3. 你声明你所依赖的东西。

  4. Composer 会找出哪个版本的包需要安装,并安装它们(将它们下载到你的项目中)。

系统要求

Composer 要求 PHP 版本在 5.3.2 以上才能运行。还需要对 PHP 做一些设置和编译标志,在安装时会收到所有的不兼容警告。

从源码安装软件替代简单的解压压缩文件,你需要 git,svn,fossil 或者 hg 这取决于软件所用的版本控制工具。

Composer 是多平台的,可以在 Windows,Linux 和 OSX 上良好运行。

安装

最简单的使用方法就是 composer 作为命令行工具使用 ,只需下载 composer.phar 文件到项目目录,执行下面命令,即可查看 composer 基本操作方法:


php composer.phar

composer

下载地址: https://getcomposer.org/download/

基本使用

若要在项目中使用 Composer 你需要一个 composer.json 文件。该文件描述了你的项目依赖关系和其他元数据。

require

首先是添加 require 参数 ,可以直接修改 composer.json 文件,也可以通过命令 composer require monolog/monolog

require 是告诉 Composer 你的项目所依赖的包有哪些 。

{
    "require": {
        "monolog/monolog": "1.0.*"
    }
}

如上所示,require 获取了一个包名称 (例如 monolog/monolog)映射到版本约束 (例如 1.0.*)的 json 对象。

此时我们使用 composer install 时,会自动根据包中的依赖关系,来安装相对应的包。

require 参数的键值分别是 包名称包版本约束

如这里的 monolog/monolog 是包名称

包版本约束

在我们使用composer安装包时,不得不考虑的就是一个版本问题,因为不同的版本,存在兼容性问题,因此我们在使用该工具安装包时需要特别的注意包版本,如果使用不当很容易导致项目因为包版本问题瘫痪。常见的几种如下:

1. 精准版本 明确要安装到那个版本,如需要安装包的版本是8.4.1

"phpunit/phpunit": "v8.4.1",

2. 通配符 既满足指定范围即可,如下范围在8.0到8.1之间

"phpunit/phpunit": "8.0.*",

3. 范围 范围常用的操作符有>,>=,<,<=,!=。你可以定义多个范围,使用空格或者逗号 , 表示逻辑上的与,使用双竖线 || 表示逻辑上的或。其中与的优先级会大于或。

// 表示大于等于0.90并且小于3.0的版本
"ruflin/elastica": ">=0.90 <3.0",

4. 波浪符 ~ 该操作符限制最小版本号。

允许表达式中的最后一位版本号达到最大值

如 ~1.2 与 (>=1.2 && <2.0)相等,~1.5.6与(>=1.5.6 && < 1.6.0)相等。也就是主版本号与次版本号保持不变,修复版本号可以达到最大值。

5. 折音符 ^

该操作符约束锁定最大版本号。
锁定表达不变的是第一位主版本号,允许升级版本到安全的版本号

如^1.2就等于>=1.2 <2.0,^1.2.3就等于>=1.2.3 < 2.0.0。

依赖类型

require 通常包括平台包依赖第三方依赖

  • 平台包包括 PHP 本身、PHP 扩展和一些系统库。
"require": {
    "ext-json": "*",
    "php": ">=7.1.0",
}
  • 第三方依赖就是开发者造的各种轮子,各种扩展包等(如七牛sdk,微信sdk等)

引入使用

为了描述包的自动加载信息, Composer 会生成一个 vendor/autoload.php 文件,你可以简单的 include 这个文件,并在无需其它额外工作的情况下就可以使用这些包所提供的类:

<?php
require __DIR__ . '/vendor/autoload.php';

$log = new Monolog\Logger('name');
$log->pushHandler(new Monolog\Handler\StreamHandler('app.log', Monolog\Logger::WARNING));
$log->addWarning('Foo');

composer.json 中还可以通过添加 autoload 指令,来添加自己的自动加载声明

{
    "autoload": {
        "psr-4": {
            "App\\": "src/" // 声明自动加载 目录映射命名空间
        },
        "files": [
            "src/helpers.php" //声明助手函数,可全局使用
        ]
    }
}

基本命令

基本命令解释
composer init初始化 composer.json 文件
composer create-project将所有的代码及其依赖的包放到一个目录下,相当于执行了一个git clone命令
composer install读取 当前目录的 composer.json 文件,解决依赖关系,并把它们安装到 vendor 文件夹中
composer update获取最新版本的依赖以及升级 composer.lock 文件
composer update [vendor/package] ]vendor/package2]获取升级部分指定包依赖
composer require [vendor/package]将新的依赖添加到当前目录的 composer.json 文件中 (可指定版本)
composer remove [vendor/package] [vendor/package2]移除 composer.json 中的扩展包
composer global require [friendsofphp/php-cs-fixer]全局依赖扩展安装,如全局 CLI 工具,phpcs
composer global update升级全局依赖扩展包
composer search monolog搜索当前项目下的包仓库
composer show列出所有可用的包

更多命令 点击查看

Packagist(composer 资源库)

Packagist 是 Composer 的主要资源库。一个 Composer 库基本上是一个包的源:一个你可以得到包的地方。

Packagist 的目标是成为一个任何人都可以使用的中央仓库。这意味着你可以 require 那里的任何包,无需指定 Composer 查找包的位置。

当你访问 Packagist 网站 (packagist.org),你可以浏览和搜索包。

建议使用 Composer 的开源项目在 Packagist 上发布包。虽然并不一定需要发布在 Packagist 上来被 Composer 使用,但它使我们的编码更加轻松。

Composer 安装时候会向国外的 Packagist 服务器发送请求,因为众所周知的原因,国内请求国外服务器,有时会出现不稳定甚至不可用的情况。

Composer 国内镜像加速

以阿里云为例,全局模式(推荐):

composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

单独项目使用:

composer config repo.packagist composer https://mirrors.aliyun.com/composer/

composer.jsoncomposer.lock

在使用composer后目录中会出现2个文件,composer.lockcomposer.json ,现在来说说这两个文件的作用。

  1. composer.json 文件中保存的是我们安装的组件及组件的版本要求。

  2. comopser.lock 文件中保存的是组件及其依赖的版本记录 , 并配合 composer install 使用,保证了团队所有协作者开发环境、线上生产环境中运行的代码版本的一致性。 在使用 composer install 的时候是不会修改composer.lock 这个文件,所以会把这个文件也放入版本管理中,其它人在使用时只需要composer install 就可以了。而使用 composer update 后会修改这个文件。

composer.lock 这个文件主要是解决在协同开发中组件及其依赖的版本记录,防止不同人使用的组件及依赖版本不同。

推荐做法

  1. 应用 (project), 就是说是独立项目而不被其它项目依赖的,是推荐把 composer.lock文件加入版本控制的,保证开发人员安装后的环境是一样的。
  2. 工具类 (library), 用于别人依赖使用的,不建议把 composer.lock 加入版本控制,因为很容易与其它包的依赖版本造成冲突。

创建扩展包

1. 创建项目仓库,新建github或者gitee 仓库

2. 创建 Composer 配置文件 composer.json 可以使用命令 compser init 创建也可以手动创建,最终文件内容大体如下:

{
    "name": "your-vendor-name/package-name", //包名
    "description": "A short description of what your package does",//描述
    "version": "1.0.0", //版本
    "type": "library", //类型 library 扩展包 project项目包
    "keywords":"composer", // 关键词
    "license": "MIT", //许可协议
    "authors": [
    {
      "name": "xxx",
      "email": "xxx@qq.com"
    }
  ],
    "require": { //声明依赖
        "php": ">=7.1.0"
    },
	"require-dev": { //声明开发依赖
        "phpunit/phpunit": "~6.5.5"
    },
    "autoload": { //自动加载
        "psr-4": {
            "App\\": "src/"  //命名空间和目录映射关系
        },
        "files": [
            "src/helpers.php" 
        ]
    },
	"repositories": { //指定仓库
        "packagist": {
            "type": "composer",
            "url": "https://mirrors.aliyun.com/composer/"
        }
    }
}

3. 提交代码到 Github 仓库 根据自己需要实现的功能编写代码,本项目最终项目结构如下:

<?php

namespace App;

class ComposerExample
{
    /**
     * 限制长度
     *
     * @var int
     */
    public $length = 6;
    
    /**
     * @param int $length
     */
    public function __construct($length)
    {
        $this->length = $length;
    }
    
    /**
     * 获取随机字符串
     *
     * @return string
     */
    public function getRandStr()
    {
        $length = $this->length;
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)]; 
        }
        return $randomString;
    }
}


<?php //helpers.php

if (!function_exists('rand_str')) {
    /**
     * 获取随机字符串
     *
     * @param int $length
     * @param string
     */
    function rand_str($length = 6)
	{
		$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, strlen($characters) - 1)]; 
        }
        return $randomString;
	}
}

composer.json

5. 发布包到 Packagist

6. 测试使用

演示地址:

  1. 新建 composer.json
{
    "require": {
        "wangningkai/composer-esample": "dev-master"
    },
    "repositories": [
        {
            "type": "vcs",
            "url":  "https://gitee.com/wangningkai/composer-example.git"
        }
    ]
}
  1. 执行 composer install

  2. 新建 demo 测试文件

require __DIR__ . '/vendor/autoload.php';

// 调用类方法
$class = new App\ComposerExample(10);
echo $class->getRandStr(); //nn3waKUwNs

// 直接通过助手函数
echo rand_str(); //cmKs6M

composer.json 文件详解

{
// ================================ 配置文件 ================================
    "name":             "your/app",
    "description":      "your-app-desc",
    "keywords":         ["composer", "php", "app"],
    "homepage":         "https://xxx.org ",
    "time":             "2016-12-30",
    "license":          "MIT",
    "authors": [{
        "name":         "wnk",
        "email":        "xxx@xxx.org",
        "homepage":     "https://xxx.org",
        "role":         "developer
    }],
    "type": "project", // library project metapackage composer-plugin
    "repositories": [
        {
            "type": "vcs",
            "url": "https://gitee.com/yii/yii-core.git"
        }
    ],
// ================================ 依赖管理 ================================
// === 默认情况下,composer只会获取稳定版本,修改后运行命令 composer install ===
    "require": {
        "php": ">=5.5.9",
        "laravel/framework": "5.1.*",
        "ignited/laravel-omnipay": "2.*",
        "lokielse/omnipay-alipay": "dev-master"
    },
// === 有些包依赖只会在开发过程中使用,正式发布的程序不需要这些包,这个时候,就需要用到另外一个键,即require-dev。例如,我们用phpunit单元测试,那么就可以通过require-dev引入这个开发环境下的依赖包
    "require-dev": {
        "fzaninotto/faker": "~1.4",
        "mockery/mockery": "0.9.*",
        "phpunit/phpunit": "~4.0",
        "phpspec/phpspec": "~2.1"
    },
    
// ================================ 自动加载 ================================
// === 加载文件最简单的方式就是require或者include, autoload,顾名思义,就是自动加载. 
// === 修改后,运行命令: composer dump-autoload, 让composer重建自动加载的信息
// === composer 提供了4种自动加载类型 classmap psr-0 psr-4 files 
// === files,对应的值是一个数组,数组元素是文件的路径,路径是相对于应用的根目录。
// === classmap,会在背后就会读取这个文件夹中所有的文件 然后再 vendor/composer/autoload_classmap.php 中怒将所有的 class 的 namespace + classname 生成成一个 key => value 的 php 数组.缺点是一旦增加了新文件,需要执行dump-autoload命令重新生成映射文件。
// === psr-0 现在这个标准已经过时
// === psr-4 支持将命名空间映射到路径。命名空间结尾的\\不可省略。当执行install或update时,加载信息会写入vendor/composer/autoload_psr4.php文件。如果希望解析指定路径下的所有命名空间,则将命名空间置为空串即可。
    "autoload": {
     "files":["lib/OrderManager.php"],
        "classmap": [
            "database"
        ],
         // FIG组织制定的一组PHP相关规范,简称PSR,其中PSR-0自动加载 PSR-1基本代码规范 PSR-2代码样式 PSR-3日志接口 PSR-4 自动加载
        "psr-4": {
            "App\\": "app/"         // 自动加载命名空间App,文件夹app里的文件
        }
    },
// 和require-dev类似,只在开发过程中自动加载
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests" // 自动加载Tests的命名空间
        }
    },
    
// ================================ 脚本 ================================
// === 在安装过程中的各个阶段挂接脚本。
    "scripts": {
        "post-install-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "pre-update-cmd": [
            "php artisan clear-compiled"
        ],
        "post-update-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "post-root-package-install": [
            "php -r \"copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ]
    },
    
// ================================ 设置 ================================
    "config": {
        "preferred-install": "dist", //Composer 的默认安装方法。 source、dist 或 auto
        "secure-http": false
    }
}

关联阅读