理解 Composer 的稳定性(Stability)标识

file

目前 composer 支持包中最常见的问题就是,对如何确定包的稳定性感到比较困惑。

这个困惑的通常表现如下例:

当引入了包 A:dev-master,但是它依赖于 包 B:dev-master, composer 会给出包 B 未能找到 的提示。

根扩展包

根扩展包是主要的 composer.json 档。他位于你运行 composer install 的资料夹。很多 composer.json 里的栏位是 root-only,表示他们只会在作为根扩展包时才会有影响。

根扩展包是一个上下文。我们说你依赖于一个扩展包 A。在你的扩展包的目录下,你的扩展包就是根扩展包。如果你 cd 进入资料夹 A,那 A 就是根扩展包。

Stability 是根据根扩展包决定的,也只有根扩展包能这么做。让他沉浸片刻,但永远不要忘记他。

Composer 将你的依赖包要多稳定的决定权交给使用者。作为一个使用者,你可以决定你想使用开发版、测试版,或稳定发行版。

minimum-stability

这种决策是基于根扩展包中的 minimum-stability  字段。它是一个唯根 字段。它给稳定性标识定义了一个默认值,并作为下限。

file

这是一个可重定义的规则。默认只展示 "stable",但是你可以改写这个规则以展示更低层的稳定性标识。

minimum-stability 定义了所有规范约束的默认稳定性标识。

稳定性解析

让我们来考虑这样一个场景:根包依赖包 A:dev-master,反过来包 A 又依赖 B:dev-master

file

根包看起来长这样:

{
    "require": {
        "A": "dev-master"
    }
}

Composer 会遵循以下步骤:

  • 确定 minimum-stability:在这里此域没有定义,所以被设置为默认值,也就是 「stable」。

  • A 约束使用版本 dev-master。由于 dev- 前缀,这是一个开发版本,开发版本有 「开发」 的稳定性。由于此开发版本的约束定义在根包,它隐式的使用 @dev 稳定性标记。

  • 既然 AA:dev-master@dev 的约束,则匹配该版本且 composer 使用这个链接。A 依赖于 B,约束为 dev-master。它有一个 dev- 前缀,所以它的稳定性为 「dev」。

但是由于约束性是定义在包 A 中而不是根包中,它不会隐式的获得 @dev 稳定性标识。取而代之的是它继承了 minimum-stability 默认使用 "stable"。所以解决约束关系使用 B:dev-master@stable

此时它会失败,因为使用 B:dev-master@stable 没法解析出任何东西。它会告诉你所提供的稳定性范围中是找不到包 B 的。

一个解决这种问题的办法就是降低 minimum-stability 稳定性到 "dev"。但是这通常都是个馊主意,因为它会应用到所有的约束规则上,最终导致 所有 的依赖包都是不稳定版本。

求神拜佛,别那么干。

稳定性标识

取而代之,应该使用稳定性标识。

稳定性标识被定义为版本约束的组成部分。因为稳定性只取决于根包,所以这个标识也是 唯根 的,在相关依赖包中定义的标识都会被忽略掉。

你可以使用标识将特定的不稳定依赖包放入白名单。这样的话就可以将包 B 放入白名单了。 如下是做法:

{
    "require": {
        "A": "dev-master",
        "B": "@dev"
    }
}

注意我并没有在根包中指定版本。这就以为着根包并不关心包 B 安装的到底是哪个版本,它将由包 A 来代为决定更具体的约束规则。
这样做的好处就是如果包 A 决定把它在包 B  上的依赖关系 dev-master 改为 ~1.0 或者其他什么的,根包无需任何改动。

Silex example

To get a better idea of how this works in practice, let's look at an example involving silex.

At the time of this writing there is no stable version of silex, which means in order to install it, you need to add a @dev flag:

{
    "require": {
        "silex/silex": "1.0.*@dev"
    }
}

Silex only has a 1.0.x-dev version, which is the dev version of the 1.0 branch.

All of the dependencies of silex have stable releases. Which means by default you will get v2.1.7 of a number of symfony components and v1.0.1 of pimple.

If you wanted to try the v2.2.0-RC1 version of those symfony components that was released a few days ago, you could whitelist them like this:

{
    "require": {
        "silex/silex": "1.0.*@dev",
        "symfony/event-dispatcher": "@RC",
        "symfony/http-foundation": "@RC",
        "symfony/http-kernel": "@RC",
        "symfony/routing": "@RC"
    }
}

Since specifying all of those versions is kind of tedious, you could lower the minimum-stability. In this case that is okay, because it is not installing unstable packages that you do not want.

{
    "minimum-stability": "RC",
    "require": {
        "silex/silex": "1.0.*@dev"
    }
}

prefer-stable

Some time after this post was written, composer got a new prefer-stable feature.

If you don't want to figure out the stability of your deps, you can just use the prefer-stable field in your root package. Composer will try to figure out the most stable deps it can.

This is quite convenient and often will get you something good enough. But I would still encourage you to think more about which stability you really want, and declaring it explicitly. You may be trading convenience for control.

结语

衷心希望这篇文章能帮你更好的理解 composer 是如何确定稳定性的,同时让你知晓如何使用稳定性标识来获取那些非稳定的版本。

牢记军规: 大部分你需要那些稳定性标识的原因,就是这些依赖的包的维护者没有给它的发行版打上标签。 你应该立刻去骚扰他们,让他们加上分支别名并打上标签。一旦他们干了这个活,你就可以把那些稳定性标签都扫荡干净,继续乐呵了。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://igor.io/2013/02/07/composer-stab...

译文地址:https://learnku.com/php/t/9929/understan...

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 1

这种翻译了一半,突然变成英文的感觉,令我猝不及防.....😂

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!