composer install才算真正锁定依赖,因其严格按composer.lock中记录的精确版本、子依赖及扩展安装,是Composer的强制契约;缺失或绕过lock文件将导致不可控的依赖重解析。

生产环境必须用 composer install,且必须有 composer.lock 文件——没它,就等于没锁。
为什么 composer install 才算真正锁定
只要 composer.lock 存在且未被绕过,composer install 就会 100% 还原其中记录的每个包、每个子依赖、甚至扩展(如 ext-json)的精确版本。这不是“大概率”,是 Composer 的强制契约。
常见错误现象:
-
CI/CD脚本里写了composer update,每次构建都拉新 patch 版本,composer.lock形同虚设 -
.gitignore里误加了composer.lock,导致团队成员composer install实际走的是update逻辑 - 本地删了
composer.lock后直接composer install,等同于全量重解析依赖树
composer install 必须带的三个参数
漏掉任一个,轻则 autoload 慢 2–3 倍,重则运行时崩溃。它们不是可选项,是生产构建的底线:
-
--no-dev:跳过require-dev里的包。否则phpunit、symfony/debug-bundle会打进镜像,还可能触发class_exists('PHPUnit\Framework\TestCase')这类运行时 fatal -
--optimize-autoloader(或-o):生成vendor/composer/autoload_classmap.php,把 PSR-4 映射编译成静态数组,跳过每次 class 查找时的文件系统遍历 -
--classmap-authoritative:告诉 autoloader “classmap 里没有的类,就真的不存在”,彻底禁用file_exists()探测——既提速,又防因符号链接或大小写问题误加载
正确写法:composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction
如何验证锁文件是否真实生效
别只看 composer.lock 在不在,得确认它装出来的包和你预期的一致:
- 用
composer show --locked查看实际安装的版本快照,字段含version(精确到6.1.8)、source.type(git还是dist)、source.reference(commit hash) - 对比
composer show --locked和composer show输出是否一致;不一致说明vendor/和lock已脱钩 - 上线前导出精简清单:
composer show --locked --no-dev --format=short > deps-prod.txt,每行格式为topthink/framework 6.1.8
最容易被忽略的一点:锁文件本身不会自动更新,它只忠实地反映上一次 composer update 的结果。所以 composer.lock 提交不及时,或者本地没跑过 update 就直接部署,锁就只是个空壳。











