生产环境必须用 composer install,因其严格按 composer.lock 的哈希与版本号还原依赖,不解析 composer.json;改用 update 会重算依赖树,易因小版本变更(如 monolog 3.5.0→3.6.0)导致 php artisan 启动失败或 500 错误。

生产环境必须用 composer install,不是“建议”,是防止崩溃的底线;任何混用 composer update、漏设环境变量或跳过锁文件的行为,都可能在部署后 5 分钟内触发 500 错误。
为什么 composer install 是唯一安全选项
它严格按 composer.lock 中记录的哈希值和版本号还原依赖,不重新解析 composer.json。一旦换成 composer update(哪怕加了 --no-dev),Composer 就会忽略 lock 文件,重新求解整个依赖树——monolog/monolog 从 3.5.0 升到 3.6.0、symfony/console 私有方法签名变更、甚至只是某个包的补丁版引入了 PHP 8.3+ 语法,都足以让 php artisan 启动失败。
常见踩坑点:
- CI 脚本里写
make deploy,背后却调用了composer update --no-dev - 手动修复线上问题时,在服务器上直接跑
composer update -
composer.lock没提交进 Git,导致composer install自动退化为update行为
composer install 必须带的三个参数和两个环境变量
缺一不可,否则不是“慢一点”,而是“启动失败”或“类加载失效”:
-
--no-dev:跳过require-dev下所有包(如 PHPUnit、PHPStan)。但注意:它只在composer.lock本身不含 dev 包时才生效;如果 lock 文件里已有 phpunit/phpunit,执行会直接报错dev dependencies not found -
--optimize-autoloader(或简写-o):生成vendor/composer/autoload_classmap.php,类加载从 1.2ms 降到 0.05ms。不加这个,高并发下 I/O 毛刺就是常态 -
--no-interaction(或简写-n):防止卡在交互提示(比如问你是否信任某个私有仓库),部署脚本里漏掉就可能无限挂起 -
APP_ENV=prod:Symfony/Laravel 依赖它决定是否启用缓存、是否跳过 dev-only 配置;漏设会导致路由未编译、.env.local被忽略 -
COMPOSER_MEMORY_LIMIT=-1:绕过 PHP 内存限制。vendor 包多时,autoloader 生成阶段极易触发Allowed memory size exhausted
推荐写成一行执行:APP_ENV=prod COMPOSER_MEMORY_LIMIT=-1 composer install --no-dev --optimize-autoloader --no-interaction
镜像源异常时如何快速止损
镜像返回非法 JSON(比如 HTML 错误页、空响应、以 {} 开头)会导致 composer install 解析失败,报错如 Invalid argument supplied for foreach() 或 JSON decode error。这不是网络不通,而是镜像反向代理层出问题。
验证方式:curl -i https://mirrors.aliyun.com/composer/packages.json,检查三点:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- HTTP 状态码必须是
200 -
Content-Type必须是application/json - 响应体必须以
{"packages":{开头
临时兜底动作:
- 切回官方源:
composer config -g repo.packagist composer https://repo.packagist.org/ - 强制刷新元数据:
composer update --refresh(≥ 2.5 版本支持);低版本则手动删缓存:rm -rf ~/.composer/cache/repo/https---repo.packagist.org/
临时目录被 open_basedir 拦截的典型表现与修复
报错类似 file_get_contents(): open_basedir restriction in effect 或 is_dir(): open_basedir restriction,本质是 Composer 在解压、缓存、生成 autoload 文件时,用到了 PHP 的临时目录(sys_get_temp_dir()),而该路径不在 open_basedir 白名单中。
快速确认方法:
- 运行
php -r "echo sys_get_temp_dir();" - 运行
php -r "echo ini_get('open_basedir');" - 若前者路径(如
/tmp)不在后者白名单里,就是它了
修复方式(不改服务器配置):
- 选一个
open_basedir允许的子路径,如$HOME/tmp/composer,创建目录:mkdir -p ~/tmp/composer - 设置两个环境变量:
export COMPOSER_CACHE_DIR="$HOME/tmp/composer/cache"和export TMPDIR="$HOME/tmp/composer" - 验证:
php -r "echo sys_get_temp_dir();"必须输出你的新路径(注意末尾斜杠必须匹配)
临时绕过验证:composer install --no-cache --no-scripts;如果这时不报错,说明问题确在缓存或脚本环节。
真正容易被忽略的是:FPM pool 配置里的 php_admin_value[open_basedir] 是强制生效、无法被 ini_set() 覆盖的,且 CLI 和 Web 请求可能走不同 pool——你在终端跑通了,不代表网页能访问。










