【问题标题】:How does the "replace" property work with composer?“替换”属性如何与作曲家一起使用?
【发布时间】:2013-09-23 19:13:53
【问题描述】:

那么“replace”属性如何与composer 一起使用?我已经阅读了作曲家文档,但仍然不明白。搜索更多信息并没有回答我的问题。

当我在 github 上查看 Laravel/Framework 上的 composer.json 文件时。我看不到替换将如何工作。有人可以向我解释这是如何工作的吗?变量“self.version”将等于什么?

【问题讨论】:

    标签: replace composer-php package-managers


    【解决方案1】:

    Composer 文档提供了两个基本示例。我会尽力解释:

    列出被此包替换的包。这允许您分叉一个包,以具有自己版本号的不同名称发布它,而需要原始包的包继续使用您的分叉,因为它替换了原始包。

    假设您的软件使用original/libraryother/package,它们本身也需要original/library

    现在您认为original/library 需要集成一个功能,但维护人员不会让您的建议出现在他们的包中。您决定以 better/library 的名义分叉该库,并标记一个新版本。

    回到您的软件。当然它应该开始使用better/library,所以你需要它,但是other/package 仍然需要original/library - 代码重复!如何让其他包使用您的 better/library 而不是分叉它,只更改 composer.json (您仍然与 original/library 兼容,所以它应该可以工作)?

    您将替换键添加到您的composer.json

    "replace": {
        "original/library":"1.0.2"
    }
    

    现在 Composer 知道,在解决 other/package 的依赖关系时,来自 better/library 的任何包都与 original/library 一样好。

    这对于包含子包的包也很有用,例如主 symfony/symfony 包包含所有 Symfony 组件,这些组件也可作为单独的包使用。如果您需要主包,它将自动满足单个组件之一的任何要求,因为它会替换它们。

    相同的规则,稍微不同的角度:对于需要某些功能的任何其他组件来说,需要框架的组件是一种很好的方法。但是,如果您需要软件中的完整框架,以及另一个库,该库随后也需要该框架的组件,则该框架的 replace 声明允许 Composer 不必安装该单个组件两次,因为它已经包含在内在完整的框架中。

    注意:替换版本中的占位符通常不好

    在我原来的回答中我建议:

    "replace": {
        "original/library":"1.*"
    }
    

    这会带来后果:Composer 现在会将您的库版本 1.0.0 视为与原始库的任何版本 1.x 一样好,即使他们修复了某些内容或添加了功能并在某天发布了版本 1.2.34。这也意味着,如果您的 other/package 某天得到更新并需要 original/library:^1.1,则 YOUR 库中的替换仍然有效,并声明它可以替换任何版本 1.*,即使没有您更新里面的任何东西 - 它不能,如果你不做一些工作,你的旧代码永远不会实现原始库的新功能,但替换说明正是这一点。

    所以本质上:在替换版本中避免使用通配符版本!如果你使用它们,你就会对你无法知道或预测的未来发表声明(除非你可以控制original/library,但即便如此也要非常小心)。始终使用您知道并且可以完全重新实现的特定版本的original/library

    【讨论】:

    • 我想我几乎明白了。所以我不明白的是composer怎么知道替换什么(用b包a或用d包c),但是composer查看类名来比较它,对吗?因此,任何名称为 a/b 的包都会被 x/b 或 y/b 替换。添加 self.version 可能意味着仅在版本号相等时替换。
    • Composer 仅检查其各自 composer.json 文件中的包名称。它不检查类名。要使技巧完全发挥作用,您必须在包中提供替换另一个包的兼容性(案例 1)。 Composer 仍会将您的 better/library 替换为 original/library,但如果原始版本中使用的类在更好的版本中没有等效的工作,代码将会失败。
    • 我遇到了另一种情况(类似于关于子包的第二个例子),这是为了避免在你知道不需要的情况下需要一些 polyfill:github.com/voku/…“如果你的项目不需要一些Symfony polyfills 请使用 composer.json 的替换部分。这消除了这些 polyfills 的任何开销,因为它们不再是您项目的一部分。"
    • @Sven,如果original/librarybetter/library 都用* 相互替换怎么办?我可以强制它使用其中之一吗?
    • @Pini:循环依赖总是一个非常糟糕的主意,我无法想象这种场景的有用用例。
    【解决方案2】:

    当你创建你自己的包时,你在composer.json 中定义了什么样的包provide 这基本上告诉Composer你的包已经安装了,所以不需要安装再来一遍。

    如果你使用replace property,它告诉 Composer 你的包想用你自己的 fork 替换原来的包,所以其他包不需要安装它。

    例如,如果a/a 包需要b/b,而您告诉替换b/b,它将不会下载到 Composer install/update

    这里有更详细的解释:How does the “replace” property work in Composer?

    【讨论】:

      猜你喜欢
      • 2016-03-05
      • 2013-12-05
      • 1970-01-01
      • 2016-11-07
      • 2017-03-13
      • 2017-02-02
      • 2018-09-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多