signed

QiShunwang

“诚信为本、客户至上”

Composer — 版本约束

2021/5/14 21:49:31   来源:

Composer 的版本约束可以分为 版本号约束 和 稳定性约束,两者结合共同影响着 Composer 的版本约束。

版本号从大到小排列,稳定性从 stable、RC、beta、alpha、dev  排列,先排版本号后稳定性。

排列例如:

v1.3  > v1.2.5 > v1.2.3 > v1.2.3-beta > v1.2.1 > v1.2.0-rc > v1.2.0-beta > v1.2.0-dev > v1.2.0

运算符

Composer 可以通过运算符控制包版本。

1.2.3

匹配具体版本。

>=1.0,<=1.2

范围匹配。有效的运算符有:>>=<<=!=。如果有多个范围,“,” 表示 逻辑AND,“|”表示 逻辑OR,AND 优先级高于 OR。

通配符 *

1.2.* 匹配 1.2.0(包含) 到 1.1(不包含)之间版本。

波浪号 ~

匹配 下一个重要版本。~ 1.2 匹配 1.2 到 2.0 之间版本。

幂符号 ^

匹配 最新而不产生兼容性问题的版本。

一横符号 -

匹配区间。5.2 - 5.4 匹配 5.2(包括)到 5.4(包括) 版本。

三段式版本号

大版本.小版本.补丁版本

  1. 如果你到软件或者库有一些 BUG 被修复了,补丁版本号 +1;
  2. 如果你增加了新功能,或者代码库增加了一个新方法,用户升级代码库后不会产生兼容问题,小版本号 +1;
  3. 如果软件完全重构,或者代码库完全重构以至于用户升级之后会产生兼容问题,大版本号 +1。

幂符号 ^ 对比 波浪号 ~

  • ~ 只能改变最末尾的版本号,例如: ~1.2.3 匹配 1.2.3(包含) 到 1.3.0 。
  • ^ 参考上面 三段式版本号 ,匹配到不产生兼容性问题的版本。也就是说除 大版本号 之外,小版本号 和 补丁版本号 都可以改变。
  • 当 版本号 只写到 小版本号 时,~ 和  ^ 匹配相同。例如 ~1.2 和 ^1.2 均匹配 1.2.0(包含) 到 2.0.0。

大版本号以 0 开头 

当 大版本号 以 0 开头,^0.3.0 匹配的是 >=0.3.0,<0.4.0。

原因

semantic versioning 规定:以 0 开头的 大版本号  表示一个 非稳定版本(unstable),处于非稳定状态下,小版本号不允许向下兼容。根据 ^ 匹配到不产生兼容性问题的版本的规则,无法改变小版本,因为改变小版本会导入兼容性问题。

⚠️ 所以 ~0.1 匹配 >=0.1,<1.0 比较危险。

😋 实践一下

根据我开头写的,先排版本号,版本号相同再排稳定性,Composer 默认会在你看出的版本控制范围之内选择安装最 “右” 版本。

实践对象

包:topthink/framework

前几个版本号:

  • 6.0.x-dev
  • v6.0.8
  • v6.0.7
  • v6.0.6
  • v6.0.5
  • v6.0.4
  • v6.0.3
  • v6.0.2
  • v6.0.1
  • v6.0.0
  • v6.0.0-rc5
  • v6.0.0-rc4
  • v6.0.0-rc3
  • v6.0.0-rc2
  • v5.2-rc1
  • v5.2-beta.3
  • v5.2-beta.2
  • 5.1.x-dev
  • v5.1.41

版本一:5.2.*@beta

使用 5.2.*@beta 版本约束,首先 5.2.* 匹配 >=5.2.0,<5.3.0,符合约束的版本并排序为 v5.2-rc1 > v5.2-beta.3 > v5.2-beta.2 ,然后看 稳定性标签 beta,因为 rc 稳定性 大于 beta,那么第一个版本 v5.2-rc1 达到要求,Composer 会安装这个版本,而不是 v5.2.beta.2 或是 v5.2.beta.3,虽然它们和 5.2.*@beta 很像。

./composer.json has been updated
Running composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 4 installs, 0 updates, 0 removals
  - Locking opis/closure (3.6.2)
  - Locking psr/cache (1.0.1)
  - Locking psr/simple-cache (1.0.1)
  - Locking topthink/framework (v5.2-rc1)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 4 installs, 0 updates, 0 removals
  - Downloading topthink/framework (v5.2-rc1)
  - Installing psr/simple-cache (1.0.1): Extracting archive
  - Installing psr/cache (1.0.1): Extracting archive
  - Installing opis/closure (3.6.2): Extracting archive
  - Installing topthink/framework (v5.2-rc1): Extracting archive

版本二:~6.0@dev

先看 版本号 约束,~6.0 表示 >=6.0.0,<6.1.0,符合条件版本根据排序第一个为 6.0.x-dev,再看 稳定性标签 dev,正好 6.0.x-dev 符合要求,Composer 会从刚才的 v5.2-rc1 升级到 v6.0.x-dev。

./composer.json has been updated
Running composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 5 installs, 1 update, 1 removal
  - Removing opis/closure (3.6.2)
  - Locking league/flysystem (1.1.3)
  - Locking league/flysystem-cached-adapter (1.1.0)
  - Locking league/mime-type-detection (1.7.0)
  - Upgrading topthink/framework (v5.2-rc1 => 6.0.x-dev c26dfea)
  - Locking topthink/think-helper (v3.1.4)
  - Locking topthink/think-orm (v2.0.40)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 5 installs, 1 update, 1 removal
  - Syncing topthink/framework (6.0.x-dev c26dfea) into cache
  - Removing opis/closure (3.6.2)
  - Installing league/mime-type-detection (1.7.0): Extracting archive
  - Installing topthink/think-helper (v3.1.4): Extracting archive
  - Installing topthink/think-orm (v2.0.40): Extracting archive
  - Installing league/flysystem (1.1.3): Extracting archive
  - Installing league/flysystem-cached-adapter (1.1.0): Extracting archive
  - Removing topthink/framework (v5.2-rc1)
  - Installing topthink/framework (6.0.x-dev c26dfea): Cloning c26dfea139 from cache

版本三:~6.0@rc

版本号约束 ~6.0 表示 >=6.0.0,<6.1.0,根据排序第一个是 v6.0.x-dev,但是 稳定性标签 rc 大于 dev,所以 v6.0.x-dev 版本被忽略。往回看第二个版本 v6.0.8 稳定性表标签 stable 大于 dev 符合要求,Composer 会从v6.0.x-dev 降级到 6.0.8。

./composer.json has been updated
Running composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 1 update, 0 removals
  - Downgrading topthink/framework (6.0.x-dev c26dfea => v6.0.8)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 0 removals
  - Syncing topthink/framework (v6.0.8) into cache
  - Downgrading topthink/framework (6.0.x-dev c26dfea => v6.0.8): Checking out 4789343672 from cache

坑一:--dry-run

require 命令有一个参数 --dry-run,进行模拟而非实际安装。但是我发现 dry-run 演示安装的版本跟实际安装的版本不一样。

例如我安装了 topthink/framework,版本号 v6.0.0,执行如下命令:

php composer.phar require --dry-run topthink/framework:~6.0@dev

结果如下。可以看到模拟从当前 v6.0.0 升级到 v6.0.8,但是我添加了稳定性标签 dev,但却不是最新 6.0.x-dev

./composer.json has been updated
Running composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 1 update, 1 removal
  - Removing opis/closure (3.6.2)
  - Upgrading topthink/framework (v6.0.0 => v6.0.8)
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 1 removal
  - Removing opis/closure (3.6.2)
  - Upgrading topthink/framework (v6.0.0 => v6.0.8)

当我直接 php composer.phar require topthink/framework:~6.0@dev 进行升级,可以正常升级到 6.0.x-dev

./composer.json has been updated
Running composer update topthink/framework
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 1 update, 1 removal
  - Removing opis/closure (3.6.2)
  - Upgrading topthink/framework (v6.0.0 => 6.0.x-dev c26dfea)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 1 removal
  - Syncing topthink/framework (6.0.x-dev c26dfea) into cache
  - Removing opis/closure (3.6.2)
  - Upgrading topthink/framework (v6.0.0 => 6.0.x-dev c26dfea): Checking out c26dfea139 from cache

坑二:~ 和 * 写一起

~6.2 就表示了 6.2.0 到 6.3,可能受到其他语言的影响,被我写成了 ~6.2.* 愣是没看出毛病,结果报错 Invalid version string "~6.0.*"

坑三:- 运算符

“-” 表示区间,但是半角状态下。其他运算符允许和版本号紧挨着,也可以空格分开;- 必须与版本号空格分开,例如:1.5.2 - 1.10。1.5.2-1.101.5.2 -1.10 1.5.2- 1.10 1.10 - 1.5.2 都是错误。

其他

Composer 提供一个在线版本控制测试网站:https://semver.mwl.be/

从左到右依次是 包名、版本号 和 稳定性标签,通过使用 运算符,网站会自动匹配并在下方标出符合约束的版本,用来学习版本控制非常好,再也不用 require 忍受国内龟速的网络了。