composer 如何处理同一个包的多个版本?
Posted
技术标签:
【中文标题】composer 如何处理同一个包的多个版本?【英文标题】:How does composer handle multiple versions of the same package? 【发布时间】:2015-01-24 20:55:52 【问题描述】:这可能(应该)以前在某个地方被问过,但我似乎找不到答案。如果有人提供链接,我可以删除此帖子!:
只是想了解一些作曲家的(可能也适用于其他包管理器)功能。
基本上我只是想知道作曲家在以下场景中做了什么:
1.
我的主项目有一个依赖:
"guzzlehttp/guzzle": "5.0.*",
我的外部包依赖于
"guzzlehttp/guzzle": "5.0.*",
composer 是否会安装一次 guzzlehttp/guzzle,因为它知道它只需要一次?
2。 相同的场景,但将来如果有人更新要使用的主项目:
"guzzlehttp/guzzle": "6.0.*",
composer 现在会安装 2 个版本的 guzzle(5 和 6)(我认为这是它应该做的),还是会安装最高版本(即 6)?此外,如果有 2 个版本,这是否会导致任何冲突,因为命名空间可能相同?
谢谢
【问题讨论】:
【参考方案1】:至问题 1
是的,Composer 只能安装每个扩展/包的一个版本。
至问题 2
因为答案 1:Composer 会认为您的主项目和外部包不兼容。
在这种情况下你可以
在您的主项目中也保留第 5 版。 如果兼容,请让外部包所有者也升级到版本 6。 fork 外部包并自行使其与版本 6 兼容【讨论】:
有没有人找到解决这个问题的方法?还是作曲家团队认为这是一个特性而不是一个错误? 我想这永远不会起作用,因为不同版本中的相同扩展/包将具有相同的命名空间和几乎相同的功能,这使得它们不兼容。这不是功能也不是错误。您根本不能在同一个命名空间中拥有 2 次相同的函数。 @peh,是的,这是真的,但是您的代码可能有两个完全不同的部分,需要两个完全不同版本的库。如果它们在加载时从不发生碰撞,那么从技术上讲可以有两个不同的版本。但就作曲家而言,它不是自动加载的,据我所知,它没有内置方法来区分自动加载的不同版本。【参考方案2】:我们今天遇到了一种情况,我们使用了多个库,其中一个使用了 Guzzle v5,另一个使用了 Guzzle v6。升级(或降级)不是一个可行的选择,因为它是第三方代码,所以我们必须能够安装两个版本的 Guzzle。
这就是我们所做的。这是一个TOTAL FRACKING HACK,我建议仅将其作为绝对的最后手段。它可以工作,但更新您的调用代码以仅使用一个版本是一个更好的选择。
诀窍是您需要重新命名两个版本之一。在我们的例子中,我们决定将 v6 更改为 GuzzleHttp6。这样做的方法如下:
-
确保您的
composer.json
已启用 v6:
"require":
"guzzlehttp/guzzle": "^6.2"
// possible other stuff
,
composer install
安装 Guzzle v6 的所有依赖项。
将/vendor/guzzlehttp
目录移至新的/vendor-static/guzzlehttp
目录。
在/vendor-static
目录中进行区分大小写的查找和替换,以将 GuzzleHttp 替换为 GuzzleHttp6。这有效地将 Guzzle 6 代码带入了一个新的命名空间。
现在更新您的composer.json
以手动包含Guzzle 自己的依赖项,然后自动加载/vendor-static
文件夹中的代码。请注意,您需要删除主要的 guzzle 要求语句(或将其更改为包括 guzzle 5);
"require":
"guzzlehttp/guzzle": "~5",
"psr/http-message": "~1.0",
"ralouphie/getallheaders": "^2.0.5"
,
"autoload":
"files": ["vendor-static/guzzlehttp/guzzle/src/functions_include.php",
"vendor-static/guzzlehttp/psr7/src/functions_include.php",
"vendor-static/guzzlehttp/promises/src/functions_include.php"],
"psr-4":
"GuzzleHttp6\\": "vendor-static/guzzlehttp/guzzle/src/",
"GuzzleHttp6\\Psr7\\": "vendor-static/guzzlehttp/psr7/src/",
"GuzzleHttp6\\Promise\\": "vendor-static/guzzlehttp/promises/src/"
,
composer update
删除旧的 Guzzle v6,并安装 Guzzle v5。这还将安装 psr/http-message
和 ralouphie/getallheaders
依赖项。
您可能需要执行composer dump-autoload
来强制自动加载器添加新的包含路径。理论上这应该发生在composer update
,但我不得不强制它。
现在更新您的呼叫代码;您将调用 \GuzzleHttp6,而不是调用 \GuzzleHttp。
就是这样。您应该能够同时运行两者。请注意,您在 /vendor-static
目录中获得的任何版本的 Guzzle v6 都将永远存在,因此您可能需要不时更新它。
【讨论】:
您是否有可能分叉了使用奇怪版本的 guzzle 并根据需要对其进行修改以使其兼容的包,然后 composer 安装了那个包?在一个完美的世界中,这将是最好的方法,它需要做更多的工作,但可以让你不必做这些变通方法。 在我们的例子中不是——使用 Guzzle5 的父库是专有的第三方代码,已使用 Ioncube 加载程序加密,并且不可更改。我们必须有一个支持 Guzzle5 和 Guzzle6 的解决方案。 这并不总是像查找和替换那样简单以上是关于composer 如何处理同一个包的多个版本?的主要内容,如果未能解决你的问题,请参考以下文章
Jetpack Compose 和 Compose Navigation 如何处理 Android 活动?
configure.ac中如何处理多个版本的Automake