私有库composer.json必须为下游让路,require字段禁用精确版本(如"2.8.0"),应改用语义化范围(如"^2.8");why-not需在私有库目录运行;禁设minimum-stability;conflict字段全局生效。

私有库不是“关起门来就能随便写约束”的地方——它一旦被多个项目或团队依赖,版本冲突就会从报错变成阻塞上线的生产问题。核心原则只有一条:私有库的 composer.json 必须主动为下游让路,而不是反过来要求所有项目迁就它。
私有包的 require 字段不能写死具体版本
常见错误是把底层依赖锁成精确版本,比如:"monolog/monolog": "2.8.0" 或 "guzzlehttp/guzzle": "7.4.5"。这等于给所有引用它的项目套上铁镣:只要另一个包要 guzzlehttp/guzzle 的 ^7.5 或 ^8.0,Composer 就立刻放弃。
- 正确做法是用语义化范围放宽约束,例如:
"monolog/monolog": "^2.8 || ^3.0"(前提是你的代码真能兼容两套 API) - 更稳妥的是只写
"monolog/monolog": "^2.8",然后靠composer test+ CI 覆盖多版本运行时验证 - 如果必须兼容旧项目还在用
monolog 1.x,那就得在私有包里做运行时分支判断,而不是靠 Composer 强制拉两个版本——PHP 不支持同名包并存
composer why-not 必须在私有库根目录下运行
很多人在主项目里跑 composer why-not vendor/private-sdk:^2.3,结果输出一堆无关路径。问题在于:私有 SDK 的约束是否生效,取决于它当前安装的版本是否来自源码(如 path repo)还是 Packagist 镜像。如果你本地用 "repositories" 指向本地路径,那 why-not 必须进那个私有库目录里跑,否则查不到它 composer.json 里的真实约束。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 进私有库目录后执行:
composer why-not monolog/monolog:^3.0,才能看到它自己是不是卡住了升级 - 若输出类似
your-private-sdk dev-main requires monolog/monolog 2.9.3,说明问题就在你自己的composer.json里 - 别信主项目里
composer show --tree显示的“已安装版本”——那是 lock 文件记录的结果,不是约束源头
私有源配置别碰 minimum-stability 和 prefer-stable
有些团队为了“方便”,在私有源的 composer.json 里设 "minimum-stability": "dev",甚至加 "prefer-stable": false。这会导致所有依赖它的项目默认接受 dev-master,而一旦某个子依赖只发布稳定版(比如 symfony/console),整个解析链就断掉。
- 私有库的
composer.json应该完全不声明minimum-stability,让它继承主项目的策略 - 发布流程里强制打 Git tag(如
v2.3.0),并确保 Packagist 同步成功,而不是靠dev-main临时顶替 - 如果真需要测试分支,用
composer require vendor/private-sdk:dev-feature/x --with-dependencies显式指定,别污染全局稳定性策略
最常被忽略的一点:私有库的 conflict 字段一旦写上,就是全局生效的硬规则。比如你写了 "conflict": {"laravel/framework": ">=11.0"},哪怕主项目没装 L11,只要某个间接依赖悄悄拉进来一个带 conflict 声明的包,Composer 就会直接报错——它不看“你用不用”,只看“有没有”。










