composer prohibits用于发布前预判冲突,需带完整版本号(如myorg/utils:2.5.0),输出末尾(for vendor/old-pkg v1.8.2)即真实卡点;空输出不保证安全,须结合composer update --dry-run -v查Because链和composer show --tree验lock锁定版本。

Composer 本身不提供“发布前预判冲突”的原生能力——它只在 require 或 update 时才真正求解依赖图。所谓“预判”,其实是通过提前模拟安装行为、检查约束交集、验证 lock 文件兼容性来逼近结果。
用 composer prohibits 模拟新包引入效果
这是最贴近“发布前检测”的操作:你想把一个新版本(比如 myorg/utils:2.5.0)推送到 Packagist,但不确定它会不会让下游项目装不上。别等用户报错,先自己跑:
- 在目标下游项目的根目录下执行:
composer prohibits myorg/utils:2.5.0 - 必须带完整版本号(
2.5.0,不能写^2.5),否则报[InvalidArgumentException] Package not found - 输出中每行末尾的
(for vendor/old-pkg v1.8.2)就是真实卡点——说明这个旧包的约束和你即将发布的2.5.0不兼容 - 如果输出为空,不代表绝对安全,只说明当前项目 composer.json 和 lock 中没显式拦住它;仍需结合
--dry-run验证
composer update --dry-run -v 看清约束碰撞点
当你改完自己的包、更新了 composer.json 中的 require 后,别直接 composer update,先看 Composer 内部怎么想:
-
composer update myorg/utils --dry-run -v会摊开整个 SAT 求解过程 - 重点盯结尾的
Because链,例如:Because laravel/framework v10.32 requires symfony/console ^6.4, and myorg/utils 2.5.0 requires symfony/console ^5.4...—— 这就是无交集的铁证 - 注意
Root requirements段落,确认是不是你自己写的"myorg/utils": "^2.5"触发了整条链崩塌 - 若看到
Found conflicting requirements下列出多个monolog/monolog范围,说明枢纽包已成瓶颈,得去 Packagist 查哪个中间版本能同时被双方接受
检查 composer.lock 是否隐含兼容性断层
很多“发布后才发现冲突”,其实是因为 lock 文件里锁死了某个旧版依赖,而你的新包要求更高——但 lock 文件不会主动报错,直到别人 install 时才暴露:
- 运行
composer show --tree myorg/utils,观察它实际拉入的传递依赖版本是否和你预期一致 - 特别注意树中是否出现
(locked to X.Y.Z),这表示该版本被 lock 文件硬性固定,哪怕你改了 composer.json 也动不了 - 对比
composer show symfony/console输出的requires列表,确认它有没有反向 require 你新包不兼容的其他包(比如phpunit/phpunit锁死symfony/console ^5.4) - 如果你的包要支持 TP6 和 Laravel 11 双生态,lock 文件里绝不能只存一套依赖;建议用
composer install --no-dev+composer install --dev分环境生成两份 lock 快照做交叉验证
真正容易被忽略的,是 conflict 字段的全局生效逻辑:哪怕你新包没直接 require laravel/framework,只要它在 composer.json 里写了 "conflict": {"laravel/framework": ">=11.0"},而下游项目某个 dev 包悄悄拉进了 L11 的间接依赖,Composer 就会在 install 阶段直接拒绝——这个拦截不看路径,不走求解,一触即发。











