用 composer 将 packagist 第三方库变成本地库

2025/05/07 PHP

之所以有这个想法,是因为部分第三方库版本约束没有做好,导致版本不匹配的库也可以安装,库版本不兼容到运行时才得以暴露,影响很大。

workerman/mqtt为例,2.1版本跟workerman/workerman:^4.0是不兼容的,但 composer.jsonrequire"workerman/workerman" : "^4.0 | ^5.0"。当然直接composer require workerman/mqtt:2.1是没有问题的,如果是在已有的workerman/workerman:^4.0项目中require可以安装2.1版本,但运行时就会产生不兼容的错误提示。

Fatal error: Declaration of Workerman\Mqtt\Protocols\Mqtt::input(string $buffer, Workerman\Connection\ConnectionInterface $connection): int must be compatible with Workerman\Protocols\ProtocolInterface::input($recv_buffer, Workerman\Connection\ConnectionInterface $connection) in /usr/share/php/programming_practice/php/php-frameworks-test/workerman4_mqtt2/vendor/workerman/mqtt/src/Protocols/Mqtt.php on line 136

如果第三方库没有及时修改,我们就需要自己来调整一下。composer默认会从packagist查询依赖地址并依此下载,在将第三方库变成本地库时,可以沿用composer的依赖加载机制。

首先将有问题的库移出vendor目录统一放到项目根目录的third_party目录中,并将当前使用的库版本"version": "2.1"记录到库的composer.json中,再将workerman/workerman的版本约束改为^5.0

$ mkdir third_party
$ mv vendor/workerman/mqtt third_party
$ vim third_party/mqtt/composer.json
{
    "version": "2.1",
    "require": {
        "php": "^8.0",
        "workerman/workerman" : "^5.0"
    },
    // ... 此处省略其它 key:value
}

接着给项目的composer.json添加搜索本地路径的键值对。

$ vim composer.json
{
    "repositories": [
        {
            "type": "path",
            "url": "./third_party/mqtt"
        }
    ],
    // ... 此处省略其它 key:value
}

现在可以再次composer require workerman:mqtt:2.1了,得到以下提示:

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires workerman/mqtt 2.1 -> satisfiable by workerman/mqtt[2.1].
    - workerman/mqtt 2.1 requires workerman/workerman ^5.0 -> found workerman/workerman[v5.0.0, v5.0.1, v5.1.0, v5.1.1] but it conflicts with your root composer.json require (^4.0).

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

这就对了,说明目前使用的就是本地的third_party/mqtt库,版本约束应该让composer检查,防患于未然。不要不兼容的库都可以安装,这样会出大问题的。

另外,composer还支持指定私有仓库,也就是可以直接将mqtt放到自己的git仓库中,如下指定仓库地址即可,注意加个新的tag作为版本号,总体上比本地库方便得多,这里就不展开了。

{
    "repository": [
        {
            "type": "vcs",
            "url": "https://github.com/xxx/mqtt"
        }
    ]
    // ... 省略其它 key:value
}

Search

    Table of Contents