ci中必须用composer install而非update,因update会重算依赖、生成新lock文件,破坏构建可重现性;install则严格按已提交的composer.lock还原版本、顺序与依赖树,确保环境一致。

CI里必须用 composer install,绝不能用 composer update —— 否则构建不可重现,线上行为随时可能漂移。
为什么 composer install 是唯一安全选项
CI不是开发机,它不参与“选版本”的决策。一旦跑 composer update,就会重解析 composer.json、重新计算依赖图、生成新 composer.lock,等于绕过代码审查偷偷升级包。昨天通过的流水线,今天可能因 monolog 的一个 patch 版本引入 BC break 或 fatal error。
composer install 则严格按已提交的 composer.lock 还原依赖树:版本、顺序、嵌套关系全部锁定。前提是 Git 仓库里必须有 composer.lock —— CI 不会帮你生成它,没这个文件,install 直接报错退出。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 常见错误现象:
Root package 'xxx' cannot be found或静默失败后vendor/为空,大概率是漏提composer.lock - 多包项目(monorepo)中,每个子包目录下都得有自己独立的
composer.lock,否则install会自动退化为update - GitLab/GitHub Actions 默认拉取 clean checkout,没缓存、没
vendor、没临时文件 —— 只靠composer.lock启动安装
~/.composer/cache 必须缓存,vendor/ 缓存反而危险
缓存 vendor/ 看似快,实则埋雷:不同 PHP 版本生成的 autoloader 不能混用;不同分支的 composer.lock 哈希下复用 vendor,会导致 Class not found 或符号链接失效。真正该缓存的是 Composer 自身的下载层 —— ~/.composer/cache,它只存 ZIP 包、git clone 快照和元数据,与运行环境无关。
- GitHub Actions 推荐写法:
path: ~/.composer/cache,key: ${{ runner.os }}-php-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }} - GitLab CI 写
cache: { key: "$CI_COMMIT_REF_SLUG", paths: ["~/.composer/cache"] },别把vendor/加进paths - 缓存失效最常见原因:
composer.lock被本地手动生成但没提交,导致 key 不匹配,每次走冷安装 - 私有包拉取失败(如
Project not found or you don't have access),基本是因为没配 SSH Agent 或 deploy key,不是缓存问题
生产部署必加的三个参数:--no-dev、--optimize-autoloader、--classmap-authoritative
这三个不是可选项,是 autoload 性能与稳定性的底线。漏掉任一,轻则加载慢 2–3 倍,重则运行时崩溃。
-
--no-dev:跳过require-dev里的包(如phpunit),避免把测试工具打进线上镜像;但若代码里写了class_exists('PHPUnit\Framework\TestCase'),就会 fatal —— 得改用class_exists(, false)或先function_exists()兜底 -
--optimize-autoloader:生成vendor/composer/autoload_classmap.php,把 PSR-4 映射编译成静态数组,跳过实时扫描 -
--classmap-authoritative:告诉 autoloader “不在 classmap 里的类,一律不存在”,彻底禁用file_exists()探测,提速且防误加载 - 三者必须一起用,且仅在生产部署阶段启用;CI 测试阶段可不加
--classmap-authoritative,但--no-dev和--optimize-autoloader建议始终开启
容易被忽略的底层细节
很多 CI 失败不是命令写错了,而是环境没对齐。
-
composer install静默失败?先检查 PHP 扩展是否齐全:ext-zip、ext-openssl、ext-pcre缺一不可,否则卡在 “Lock file operations: 1 install, 0 updates…” 就不动了 - PHP 版本不匹配会出诡异问题:如果
composer.json里写了"config": {"platform": {"php": "8.2.0"}},而 CI 中用的是8.2.1,Composer 会模拟 8.2.0 解析依赖,可能导致ext-gd等扩展判断失准 - 内存限制常被忽视:某些 CI 镜像默认
memory_limit=128M,composer install直接 OOM;应在脚本开头加export COMPOSER_MEMORY_LIMIT=-1或显式设为2G - 私有 Packagist 镜像或 token 变更不会反映在
composer.lock中,但会影响下载行为 —— 这类配置需通过环境变量(如COMPOSER_AUTH)注入,而非硬编码在composer.json










