composer install 是唯一该进 CI/CD 和上线流程的命令,因其严格按 composer.lock 还原确定版本,保障可重现性;composer update 会忽略 lock、重解依赖,可能引入不兼容变更,必须人工触发并审查 diff。

团队项目里,composer install 是唯一该进 CI/CD 和上线流程的命令;composer update 只能由人手动触发,且必须配合 git diff composer.lock 审查变更。
为什么不能在 CI 里跑 composer update
它会忽略 composer.lock,重新解析整个依赖树 —— 即使 composer.json 没动,也可能因上游包发布新版本而装上不兼容的 symfony/console 或 ext-json 行为变更。现象包括:本地正常、CI 报 Class not found,或 PHP 8.2 下 json_encode() 返回 null 而非 false。
-
composer install严格按composer.lock还原环境,是可重现性的底线 -
--no-dev必须加在生产环境命令里:composer install --no-dev,否则phpunit、laravel/pint会白装几十 MB - CI 第一步建议加
ls -la composer.lock,防止缓存导致误用旧 lock 文件
require 和 require-dev 划分错误的典型表现
错放一个包,就可能让线上容器多启一个无用进程,或引发类名冲突。判断标准很简单:运行时是否被 autoload 加载并执行?
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 放进
require的:真正参与业务逻辑的,比如doctrine/dbal(迁移要用)、guzzlehttp/guzzle(HTTP 调用) - 放进
require-dev的:只在开发/测试阶段起作用的,比如phpunit/phpunit、roave/security-advisories(它本身不提供代码,只做安装拦截) -
symfony/var-dumper这类调试工具,如果只在APP_DEBUG=true时加载,也应进require-dev,避免污染生产 autoload 映射
composer.lock 被忽略或没提交,后果不是“可能出问题”
是“一定出问题”,而且问题会逐层放大:某人本地没提交 lock → 新人 composer install 装的是旧版依赖 → 测试通过 → 上线后因 monolog 日志格式变更导致告警失灵。
-
.gitignore里绝不能有composer.lock -
composer.lock和composer.json必须同时提交,且语义匹配:比如composer.json里"config": {"platform": {"php": "8.2.0"}},lock 文件里的platform字段也得是8.2.0,否则 CI 可能绕过平台约束装错扩展 - 团队可约定:每次
composer update后,必须git add composer.json composer.lock一起提交,不接受只提 json
本地想试新版本,但又怕搞乱环境
别直接 composer update 全量升级,风险不可控。精准控制才是关键。
- 先
git status确认工作区干净,避免 lock 变更混入其他修改 - 只更新单个包:
composer update vendor/package-name,比如composer update laravel/framework - 锁死小版本再更新:
composer require vendor/package-name:^10.3.0,比update更透明 - 更新完立刻
git diff composer.lock,重点看是否波及了ext-*或php平台要求
最常被跳过的其实是 platform 配置和 composer.lock 的语义一致性 —— 它们不报错,但会让不同机器上的“相同 PHP 版本”实际加载不同的扩展行为。

















