发布于2026-07-06 阅读(0)
扫一扫,手机访问
先说一个很多人踩过的坑:在 composer.json 里只配了 "prefer-stable": true,结果生产环境还是装进了 beta 或 dev 包。问题出在哪?答案很简单——这两个配置必须同时上场,缺一不可。
必须同时配置"minimum-stability": "stable"和"prefer-stable": true,缺一不可;只设其中一个,生产环境大概率仍会装进beta、rc或dev包。

prefer-stable 不起作用很多人以为 prefer-stable 就是个“我要稳定版”的开关,其实它更像一个排序偏好,而不是准入规则。它的生效前提是:候选版本池里已经装满了“合法”的选项。如果没配 minimum-stability,Composer 在 2.2+ 版本下默认行为虽然是 "minimum-stability": "stable",但老项目、某些插件或自定义配置可能会悄悄绕开这个默认值,导致解析出来的是 dev-main 或 2.0.0-RC1。
prefer-stable: true 单独存在时,不会阻止 "monolog/monolog": "dev-main" 这类显式声明的开发版——说白了,你点名要开发版,它不会自作主张给你换成稳定版。composer.lock 锁着某个 dev 版本,composer install 根本就不会去看 prefer-stable 的配置,直接照装不误。composer config -g prefer-stable true 在 Composer 2.2+ 已被移除,运行结果要么静默失败,要么直接报错。minimum-stability 和 prefer-stable 的真实分工简单来说:minimum-stability 是门槛,prefer-stable 是排序器。前者决定“谁能进候选池”,后者决定“谁先被挑中”。
"minimum-stability": "beta" 加上 "prefer-stable": true,候选池里可能会包含 1.2.0(stable)、1.3.0-RC1、1.3.0-beta2,这时 Composer 会优先选 1.2.0。1.2.0 根本不符合你声明的版本约束(比如你写了 ^1.3),那它连候选池都进不了,再怎么 prefer 也没用。"minimum-stability": "dev",它的子依赖就可能越过你的全局设置。解决办法是单独用 "vendor/pkg": "^2.5@stable" 显式卡住。composer update,不是 install这点经常被忽略。修改了 composer.json 之后,运行 composer install 只会读取 composer.lock 里的锁死版本,新配置跟它毫无关系。只有 composer update(或者带 --lock 的变体)才会重新走一遍依赖解析流程,把 prefer-stable 真正应用进去。
composer update monolog/monolog,它会尊重新配置并重新选择版本。vendor/ 目录里已经存在旧的 dev 包,update 会尝试替换;但要是锁文件里仍然记着 "reference": "a1b2c3d",就得先删掉 composer.lock 和 vendor/,再重新 composer install 重建。update,上线后跑的还是 dev 版本,到时候排查起来可够呛。很多团队在预发环境用了 dev-develop 做测试,上线时只改代码、不碰依赖,结果 composer.lock 里还锁着 "version": "dev-develop" 或者带 "reference" 的 commit hash。后果是什么?
composer install 要么直接失败,要么拉下来的内容跟你预想的不一样。grep -A3 '"monolog/monolog"' composer.lock | grep version,确认输出的值是 "2.9.3" 这类纯语义化版本,而不是 "dev-main"。composer require monolog/monolog:^2.9,让 Composer 主动锁定稳定版。一句话:别让 dev 版本成为线上的隐形冲击波。