如何发布自己的composer包?

如何发布自己的composer包?

composer简介

是PHP用来管理依赖(dependency)关系的工具。你可以在自己的项目中声明所依赖的外部工具库(libraries),composer 会帮你安装这些依赖的库文件,你也可以写自己的工具库让别人下载使用。

其实composer就是一个跟js的npm,RedHat/CentOS的yum,Ubuntu的apt/apt-get,macOS的brew类似的工具。

安装composer

composer工具的本质

composer其实是用php写的一个php包管理工具(官方叫依赖管理工具),它的文件名叫composer.phar,phar是PHp ARchive的缩写,中文直译可以称为“php归档文件”,是的一种包封装技术(其实就是一种压缩包),类似java的.jar文件。

我们可以把composer.phar解压出来看看,在终端进入composer.phar所在目录,执行以下代码即可解压:

php -r "(new Phar('./composer.phar'))->extractTo('composer');"

解压完之后,你就能看到它的源码就是php,特别是它的bin/composer文件,并没有后缀,你可能会以为它就是一个二进制可执行文件,但其实它就是一个php写的程序,只不过没有以.php结尾而已。

如果在phpstorm看就更简单,直接可以看,都用不解压:
-w1440

这也就是为什么很多文档里使用composer的时候,是这样用的,比如安装monolog:

# 安装monolog
php composer.phar require monolog/monolog

但是你去Packagist看,它的安装命令是这样的:

composer require monolog/monolog

所以以上两句命令中的composer.pharcomposer有什么不同呢?其实没什么不同,composer就是composer.phar,看官方文档的全局安装,如下图,它是直接把composer.phar移动到/usr/local/bin/目录下,并且是重命名为composer了,即把后缀.phar去掉了:
-w827

因为/usr/local/bin/肯定是在环境变量里,所以在终端哪个位置都能执行composer了(即可以全局执行了)。

可是,php写的包,为什么不用php去执行它也可以呢??比如我们执行一个php文件,肯定得php index.php这样执行它呀,直接./index.php是不行的,但真的不行吗?其实并不是不可以,我们可以看看shell脚本和python是怎么做的!

把以下代码保存成test.sh,并赋予权限chmod 755 test.sh,然后用./test.sh运行:

#!/bin/sh
echo "this is a test!"

其实,你不写#!/bin/sh,只写代码,最后用bash test.sh一样可以执行的。

python脚本也一样:

#!/usr/bin/env python
print('this is a test!')

你在里面写了#!/usr/bin/env python,并且赋予了执行权限,那就可以用./test.python这样运行,但如果你不写#!/usr/bin/env python,也是可以直接python test.python这样执行的。

php也是同理,里面也可以写#!/usr/bin/env php,并且赋予权限,就可以用./test.php这样执行的。

还有人会觉得,为什么去掉.phar后缀,也能执行呢?其实稍微有点Linux常识的童鞋应该都知道,后缀在Linux里只是给人看的,机器是完全不看后缀的,比如php test.php,你完全可以把.php去掉,变成php test,一样可以执行的,又比如test.tar.gz,你去掉.tar.gz,一样可以用tar -zxf test解压,只不过没有后缀,我们人就不知道它是什么文件,所以要加后缀。

我认为composer能直接执行是因为有这个stub.php的原因,应该是.phar包有一定要机制自动从stub.php这里开始执行吧:
-w1398

Mac/Linux安装composer

手动全局安装composer用以下:

# 用curl下载installer(它是个php写的文件),然后通过管道符交给php执行,其实也就是下载composer.phar
curl -sS https://getcomposer.org/installer | php
# 把composer.phar移动到/usr/local/bin/目录下,并且重命名为composer
mv composer.phar /usr/local/bin/composer

这种手动安装的方法,Mac和Linux都是可以的,不过Mac有更简单的安装方法:

brew install composer

其实原理是一样的,无非就是下载composer.phar并放到合适的地方,然后加入到环境变量里。

Windows安装composer

手动安装:
由于Windows不能像Mac/Linux那样用#!/usr/bin/env php的方式去指定执行,所以在Windows上的composer本质还是需要用php composer.phar这样的方式去执行的,但我们也可以配置成全局的composer命令,其原理,就是通过批处理文件去执行php composer.phar这个命令。

具体做法,在适当的目录新建一个名为composer的文件夹,下载最新版的composer.phar放到这个文件夹中,再在该文件夹下新建一个composer.bat文件,文件的内容如下:

@D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.exe "%~dp0composer.phar" %*

其中这个是php.exe的路径:

D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.exe

%~dp0中的dp表示drive path,磁盘路径,%~dp0就是指当前目录,相当于php的__DIR__

%*表示参数,%0是第一个参数,%1是第二个参数,%2表示第三个参数,……

最后把composer.bat添加到环境变量中即可(点击图片可放大):
-w1760

其实前面那个php的路径,也可以加入到环境变量,这样composer.bat里就可以这样写,就简单多了:

@php "%~dp0composer.phar" %*

可执行文件安装:
下载Composer-Setup.exe,然后自己安装即可。

创建自己的composer包

只要你的代码文件夹里有一个composer.json文件,那么这个文件夹就是一个composer包了,关键就在于composer.json要怎么写,最简单的方法,其实就是看一看现有项目中的vendor里安装的包,看它们的composer.json是怎么写的,看它们都是什么结构,多看几个,模仿模仿就清楚了。

composer包的结构

包名的格式是“供应商名称/项目名”,比如阿里云对象存储的php-sdk:oss-sdk-php,它的包名是“aliyuncs/oss-sdk-php”,其中“aliyuncs”是供应商名称,“oss-sdk-php”是项目名称。

供应商名(文件夹)          # 供应商一般是公司名(个人项目可写github名或与包名相同的名称)
└── 包名(文件夹)          # 即你的项目名称
    ├── LICENSE         # 版权文件,非必须,但如果没特殊版权一般都建议用MIT协议
    ├── README.md       # 使用文档,非必须,但基本上都要有比较好,你没文档人家不知道怎么用
    ├── composer.json   # 必须,一个包它是不是composer包,就靠这个文件
    └── src(文件夹)      # 源码文件夹,非必须,如果没有文件夹直接在包名文件夹下也可以
    └── tests(文件夹)    # 测试代码文件夹,里面放测试类、测试代码

在包名文件夹下,还可以写自己想写的文件,上边没有列出,因为每个人想写的不一样,所以没固定规则,比如CHANGELOG.md,又比如有中英文文档的,除了README.md,还会有README-CN.md等等。

文件夹结构如下图所示:
Xnip2019-09-06_16-22-59

源码可以直接放在src目录下,也可以以一个文件夹的形式放在src目录下,而且很多包都这么做(原因可能是以前已经写好了,只不过是要搬到composer上来,所以把整个文件夹复制到src里即可),比如:
阿里云的对象存储php-sdk:
-w258

腾讯云对象存储php-sdk:
-w268

七牛云对象存储php-sdk:
-w270

创建一个composer包

如果想要别人能用composer下载你的包,那么你必须把你的包上传到Packagist上,而Packagist是无法直接上传的,一般情况下都是从github同步过去的,所以我们要把我们写好的包上传到Github,而想要把写好的代码上传到github,最好是先在github上创建一个项目再克隆下来,添加代码后再提交,这样是最方便的,当然也有另一种方法,请查看:怎样把一个新项目/本地项目提交到github?

在github创建项目特别简单,如下图所示,点击右上角的+号,点击New repository,然后按下图的提示填写,最后点击Create repository即可创建:
Xnip2019-09-08_20-18-55

上图创建成功后来到这里,这里已经有项目的git地址了:
-w1103

根据上边得到的git项目地址,在本地你想保存代码的地方git clone下载(我是在~/www/personal/目录下执行以下代码的):

git clone https://github.com/xiebruce/learn-composer.git

如下图所示:
-w727

在上面git clone下来的“learn-composer/”目录里创建srctests两个目录,并创建一个.gitignore文件,然后在src目录下创建一个类文件HelloWorld.php
结构如下:

├── src                 # 源码目录
│   └── HelloWorld.php  # 源码类文件
├── tests/              # 测试代码目录
├── .gitignore          # git忽略文件
└── LICENSE             # 版权文件
└── README.md           # 说明文档

HelloWorld.php类里的代码如下:

<?php
/**
 * Created by PhpStorm.
 * User: Bruce Xie
 * Date: 2019-09-09
 * Time: 12:31
 */

// 关于这个命名空间名称,你可以随便写。当然,如果src目录下还有一层目录,则一般都写这层目录的名字。
// 如果没有,也可以写公司简称,即“供应商名/项目名”中的“供应商名”,如果是个人项目,可以写github用户名,
// 这里我就随便写一个“pack”,这样更好的说明这是可以随意写的。
namespace pack;

class HelloWorld {
    public function sayHello(){
        echo 'Hello world!';
    }

    public static function sayHelloStatic(){
        echo 'Hello world static';
    }
}

如下图所示:
-w1437

规则:
– 文件名必须是类名.php,如文件名为HelloWorld.php,则该文件里的类名一定是HelloWorld
– 类名用驼峰命名法,并且首字母大写,如HelloWorld(驼峰命名法跟首字母大写都不是强制,而是一种规范,也就是你不按驼峰命名法,首字母不大写,程序一样可以运行)。

初始化为composer包

上边只是写了代码,但它还不是composer包,因为它缺少一个composer必须的文件composer.json,创建composer.json文件有两种方法:

  • 方法一:自己新建文件composer.json文件,然后自己写;
  • 方法二:用composer init命令创建。

方法一需要你知道怎么写一个composer.json,一般可以从别人的包里拷贝一个过来,再改改就可以。

方法二相当于是一个向导,以下我们用向导创建。在终端中进入项目文件夹learn-composer/,运行composer init即会开启向导,如下图所示:
-w956

它要你填的信息有以下信息(这些信息有哪些值可以查看:composer.json 架构):

  • Package name,即包名,前面说过,composer包名格式为供应商名/项目名,它的默认值,就是当前电脑用户名/项目名。一般来说,如果是公司项目,供应商名就是公司英文简称或拼音之类的,比如亚马逊的aws(Amazon Web Services)、阿里云的aliyuncs(aliyun cloud services)、腾讯云的qlcoud(q我不知道意思,我觉得是qq的意思)、网易云的netease、七牛云直接就是七牛的拼音qiniu,如果是个人项目,一般你可以直接用你github上的用户名,因为这样能让你的包跟github名对应,;
  • Description,项目描述,简单的说就是你这个项目是干嘛用的,不用太长,简述就行;
  • Author,项目作者,我这里是自动提示是否使用给出的姓名和邮箱,我也不知道它为什么知道我的姓名和邮箱的;
  • Minimum stability,最低稳定版本,它有dev(开发版)、alpha(内测版)、beta(公测版)、RC(Release Candidate,即候选发布版)、stable(正式发布版,即稳定版),具体可查看Package links以及理解Composer的稳定性(Stability)标识
  • Package Type,一般情况下都是填library(不填则默认是library),这种包类型,用户使用composer require xxx/xxx的形式安装后,会自动放在vendor/目录下,这也是我们最常用的类型。 具体可查看:安装类型 type
  • License,版权协议,下图是阮一峰博客的图:
    License
  • Define your dependencies,定义你这个包依赖于哪些包,这个填no就行,因为如果有依赖的话,我们可以自己修改composer.json

最后它会显示出一个json,问你是否确定要生成,输入yes,回车,即可生成一个composer.json如下:

{
    "name": "xiebruce/learn-composer",
    "description": "This is a test.",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Bruce Xie",
            "email": "[email protected]"
        }
    ],
    "minimum-stability": "dev",
    "require": {}
}

我们可以看到,其实这个composer.json非常简单,不用composer init,自己新建自己从别的地方复制一个来改改也行。

但其实这个composer.json还无法让你这个项目成为一个“composer包”,因为最重要的自动加载(autoload)没有写,我们加上autoload和require,变成这样:

{
    "name": "xiebruce/learn-composer",
    "description": "This is a test.",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Bruce Xie",
            "email": "[email protected]"
        }
    ],
    "minimum-stability": "dev",
    "require": {
        "php": "7.0"
    },
    "autoload": {
        "psr-4": {"pack\": "src/"}
    }
}

require就是指这个包要依赖什么,目前暂时写php需要大于7.0,其它的没有依赖。

autoload是关键中的关键,composer的工作原理就是靠这个。psr-4是PHP Standard Recommendations-4(第四条推荐规范),这个是推荐规范,并非标准,不过也跟标准差不多了。

{"pack\": "src/"}表示pack\命名空间对应src/目录,pack\中两个反斜杠是因为反斜杠本身是有特殊意义的,表示“转义”,如果要表示反斜杠本身就得再加一个反斜杠,相当于前面的反斜杠把后面的反斜杠转义成普通反斜杠。
image

写好composer.json后,在终端中进入项目目录,我这里是“~/www/personal/learn-composer”,运行:

composer install

运行之后,就会多一个vendor目录,vendor目录结构如下:

vendor
├── autoload.php
└── composer
    ├── ClassLoader.php
    ├── LICENSE
    ├── autoload_classmap.php
    ├── autoload_namespaces.php
    ├── autoload_psr4.php
    ├── autoload_real.php
    ├── autoload_static.php
    └── installed.json

其中的autoload.php就是我们要使用vendor中的各种包时要引用的文件。

现在我们在tests目录建一个测试文件test.php,里面代码为:

<?php
    /**
     * Created by PhpStorm.
     * User: Bruce Xie
     * Date: 2019-09-09
     * Time: 12:48
     */

    // 引入autoload.php文件,用于自动加载vendor中的库
    require '../vendor/autoload.php';

    // use HelloWorld类
    use packHelloWorld;

    // 实例化HelloWorld类
    $obj = new HelloWorld();
    // 使用对象调用sayHello()方法
    $obj->sayHello();

    echo PHP_EOL . "--------" . PHP_EOL;

    //使用类名调用sayHello()方法(静态调用)
    HelloWorld::sayHelloStatic();

如图所示:
image

在这里我们可以不使用网页来测试(当然你用网页也一样的),直接在终端进入tests/文件夹,然后执行:

php test.php

输出结果(说明调用成功):

Hello world!
--------
Hello world static

到这里就已经创建好一个包了,现在就可以提交了,提交前可以去看看.gitignore文件,把/vendor//composer.lock添加到.gitignore文件中,表示/vendor/整个目录和/composer.lock文件都不提交到github(因为在用composer下载的时候vendor会自动生成的):

/vendor/
/composer.lock

如果是真实项目,还要把使用文档在README.md文件中写一下,最后把这个包推送到github。

操作截图(点击图片可放大):
-w1014

推送到github后,刷新一下github,代码已经在这里了:
-w1015

把代码从github同步到Packagist

进入Packagist,先登录(可以用github账号登录),然后点击右上角的Submit,填上前面提交的github地址,点击Check
-w1500

如果有检测到有类似的包,它会显示出来,如下图所示,我这个包就有两个一样名字的,当然只是项目名相同,因为包名是用户名/项目名,所以包名肯定是不同的,最后点Submit,它就会自动从github克隆到Packagist中:
-w745

上图稍等片刻即会跳转到这里,表示已经同步过来了:
-w778

每次更新代码到github后,需要手动点击一下上图中的Update按钮,把Github的更新同步过来。

设置自动从Github更新到Composer

即设置每次你git push把新代码上传到github时,让github自动把这些更新的代码推送到Packagist中,这样你就只管更新github就好了,否则的话,你每次更新github代码后,还要到Packagist中手动点Update

在Packagist中查看你的包,如下图所示,点击GitHub Hook
-w752

上图点击GitHub Hook,往下滑,找到下图所示的位置,即可看到如何设置自动从Github更新到Packagist的方法,红框中的参数,就是一会儿在Github那边要填的:
Xnip2019-09-06_15-01-18

在Github上找到你要自动同步到Packagist的包,点击Settings
-w1002

再点击WebhooksAdd webhook
-w1330

上图点击Add Webhook后要输入Github登录密码:
Xnip2019-09-06_14-32-09

上图输入密码后就会来到下图所示页面,其中的Payload UrlContent TypeSecretWhich Event就是前面GitHub Hook页面中的内容:
-w1004

上面的Secret就是这里的API Token:
image

点击Add webhook添加后,就来到这个页面,这就表示添加成功了:
-w1027

添加后,回去刚才Packagist这里(这是刷新前,可以看到有个提示“This package is not auto-updated”,意思是这个包不是自动更新的。):
-w778

刷新后(刷新后就没有那个提示了):
-w538

然后就可以试试git push更新代码到Github后会不会自动更新到Packagist里,最简单的就是修改一下README.md,推送到github后,去Packagist里刷新一下就可以看到是否已经更新过来。

下载使用

假设我有一个项目叫“test-learn-composer”,新建test-learn-composer目录,在终端中进入该目录下,运行以下命令安装我们刚上传的“learn-composer”包:

composer require xiebruce/learn-composer

上边这句命令直接执行是报错的:
-w894

报错的原因是因为我们不指定版本它默认是稳定版本,所以以上命令其实相当于:

composer require xiebruce/learn-composer:stable

而我们提交的版本是dev-master的(如下图):
-w1203

所以我们要指定这个版本才能下载:

composer require xiebruce/learn-composer:dev-master

在项目文件夹下,即“test-learn-composer”文件夹下新建一个index.php,内容如下:

<?php
   // 引入autoload.php文件,用于自动加载vendor中的库
    require 'vendor/autoload.php';

    // use HelloWorld类
    use packHelloWorld;

    // 实例化HelloWorld类
    $obj = new HelloWorld();
    // 使用对象调用sayHello()方法
    $obj->sayHello();

    echo PHP_EOL . "--------" . PHP_EOL;

    //使用类名调用sayHello()方法(静态调用)
    HelloWorld::sayHelloStatic();

其实就是把“learn-composer”里的test.php复制过来,只不过把require autoload.php的相对路径换一下:
image

然后调用一下看是否正常:

php index.php

正常的话会像下图一样输出所调用的方法中echo的字符串:
image

如果想不用加:dev-master,那就要打tag发版本:

git tag -a v0.1 -m "v0.1"

把tag推送到github:

git push origin v0.1

这样就可以用以下命令这样安装了:

composer require xiebruce/learn-composer

如果要删除tag:

#先删除本地
git tag -d v0.1
#再删除github
git push origin :refs/tags/v0.1

但其实这还有问题,就是composer.json里的“minimum-stability”的值,一开始我们设置的是dev,现在要把它改成stable,重新打tag再提交。

因为composer完整命令格式其实是这样的:

composer require 供应商名/项目名:分支名@最低稳定性

对应到真实的例子就是:

composer require xiebruce/learn-composer:[email protected]

平时我们安装的时候是不写:分支名@最低稳定性的,分支名不写就默认当前最新版本,所以如果没有发版本(即没有打tag)的情况下你不写分支名它是会报错的(就跟上面那样),而“最低稳定性”如果不写,它默认是stable,也就是说我们前面用的这个命令:

composer require xiebruce/learn-composer:dev-master

按道理应该相当于这样的:

composer require xiebruce/learn-composer:[email protected]

如果你不写@stable,它会自动识别出dev-master是dev-开头的,所以会认为你要下载的是dev版本的。

打赏

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

如何发布自己的composer包?