conflict字段仅在composer install/update依赖解析时,当实际选中的包版本落入其声明范围内才报错;它不回溯检查lock文件、不阻止手动require,且须用标准版本约束语法与require共同参与SAT求解。

conflict 字段不是“解决冲突”的工具,它只在依赖解析失败前一刻报错,且必须写对版本约束才生效。
conflict 什么时候会真正触发报错
它只在 composer install 或 composer update 过程中,当 Composer 实际解析出某个包的版本落在你写的 conflict 范围内时,才中断并报错。已锁在 composer.lock 中的旧版本不会被回溯检查,哪怕它本该被禁止。
- 手动
composer require vendor/package:1.2.3成功后,只要不运行update,就不会触发校验 - 如果冲突来自间接依赖(比如 A → B → C),而降级 B 就能绕过 C,Composer 可能选降级而非报错
- 报错信息里通常不直接出现
conflict字样,而是表现为Your requirements could not be resolved,需配合-v查看Conclusion行
conflict 的写法必须严格匹配 Composer 版本语法
键是包名(如 monolog/monolog),值必须是标准版本约束,不能是分支名、dev- 前缀或空对象。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- ✅ 正确:
"conflict": { "php": "=8.2.5" }(平台包合法) - ✅ 正确:
"conflict": { "guzzlehttp/guzzle": "^7.0" }(封死整个大版本) - ❌ 错误:
"conflict": { "laravel/framework": "dev-main" }(分支名不参与解析) - ❌ 错误:
"conflict": { "symfony/console": "*" }(*在 conflict 中等价于未声明) - ❌ 错误:
"conflict": { "myorg/mylib": {} }(空值被忽略)
conflict 和 require 同时存在时,Composer 怎么处理
它们不是谁优先的问题,而是被一起喂给 SAT 求解器做逻辑交集判断。Composer 会尝试找一个同时满足 require 范围、又避开 conflict 范围的版本。
- 例如:
"require": { "monolog/monolog": "^3.0" }+"conflict": { "monolog/monolog": "^3.5" }→ 解析器只能选3.0–3.4.x区间内的版本 - 若交集为空(比如
require要^2.0,conflict排除所有),则直接失败,不提示替代方案 - 如果你在
require中锁死了foo/bar:1.2.3,又在conflict中写了"foo/bar": "^1.2",Composer 会拒绝解析——哪怕 1.2.3 明确落在冲突范围内
CI 和本地开发中最容易漏掉的验证点
本地可能因缓存、旧 composer.lock 或手动 require 绕过检测,但 CI 必须暴露真实冲突。
- 光跑
composer install不够,必须加composer update --dry-run --no-interaction - 确保你的包实际出现在最终依赖图中:如果只放在
require-dev里,它的conflict规则根本不会被加载 - 注意
config.platform的影响:如果根项目设了"platform": { "php": "8.1.0" },那么"conflict": { "php": " 就会失效——因为平台声明覆盖了真实环境
最常被忽略的是作用域和时机:conflict 不是运行时防护,也不管你已经装了什么,它只在新依赖图生成那一瞬间起作用。写错一个符号、漏掉一个版本号,它就等于没写。

















