离线环境必须配置cache-files-dir而非cache-dir;后者仅为缓存父目录,不控制ZIP包存储位置,只有files/子目录下的ZIP包支持离线复用。

离线环境必须用 cache-files-dir,不是 cache-dir
配 cache-dir 对离线毫无作用——它只是缓存父目录,不控制 ZIP 包存放位置;真正决定能否离线复用的是 cache-files-dir,且它必须显式指向一个以 /files 结尾的绝对路径(比如 /opt/composer-offline-cache/files)。否则 Composer 会回退到默认的 ~/.composer/cache/files,而离线机上这个路径通常为空或不可写。
常见错误现象:
- 明明设了
cache-dir,断网后仍重下所有包 -
composer diag显示 Cache files directory 是~/.composer/cache/files,说明cache-files-dir没生效 - 复制了缓存目录过去,但路径末尾漏了
/files,导致 Composer 根本不读
正确做法:
- 在线机先清旧配置:
composer config --global --unset cache-dir - 只设一项:
composer config --global cache-files-dir /your/shared/cache/files(注意结尾/files) - 触发完整下载:
composer install --prefer-dist --no-autoloader --no-scripts,确保 ZIP 全落进/files子目录 - 验证:
ls /your/shared/cache/files/*/*/?.*.zip应有大量文件
--optimize-autoloader 在离线部署中要慎用
离线环境往往资源受限(比如无 opcache、低内存),--optimize-autoloader 能把所有类路径预生成进 vendor/composer/autoload_classmap.php,跳过运行时遍历,对加载速度确有提升。但它也有硬约束:
- 必须配合
--no-dev使用,否则 dev-only 的类也会被塞进 classmap,浪费空间 - 一旦启用
classmap-authoritative,Composer 就彻底放弃 PSR-4 动态查找——如果依赖里有运行时注册类的逻辑(如某些 Laravel Service Provider),会直接报Class not found - 离线机若没清理旧
vendor/,旧 classmap 可能映射到已删除的路径,静默失败
建议策略:
- 在线机打包前执行:
composer install --optimize-autoloader --no-dev --prefer-dist - 离线机部署后,检查
vendor/composer/autoload_classmap.php是否存在且大小合理(几 MB 算正常) - 不要在
composer.json里全局开optimize-autoloader,避免误传到开发环境
--apcu-autoloader 在离线机上基本不可用
APCu 缓存依赖 PHP 扩展和共享内存段,离线环境通常不具备这些条件:
- 容器或精简系统常未安装
apcu.so,extension=apcu.so配置缺失 - 即使装了,
apc.enabled=1和apc.shm_size也需手动调优,离线机很难统一配置 -
--apcu-autoloader必须与--optimize-autoloader同时使用,否则无效——这意味着你得先搞定 classmap,再叠加 APCu,链路更长、容错更低 - Docker 场景下,APCu 默认仅 CLI 模式启用(
apc.enable_cli=0),FPM 进程无法共享缓存
结论:离线部署优先保稳,跳过 APCu。真要加速,靠 --optimize-autoloader + 完整 ZIP 缓存更可靠。
离线机启动前必须验证三件事
很多“缓存失效”问题其实出在路径、权限或配置残留上,不是 Composer 本身的问题:
-
composer config --global cache-files-dir输出的路径,必须和你复制过去的/files目录完全一致(包括末尾斜杠) - PHP 进程用户(如
www-data或nginx)必须对整个/files目录有read+execute权限,否则stat()失败,Composer 静默 fallback 到重下 - 确认没有残留的
cache-dir配置:composer config --global --list | grep cache,只要看到cache-dir行,就说明cache-files-dir被忽略
最易被忽略的一点:离线机上的 /files 目录层级不能被扁平化。必须保留原始结构,比如 /monolog/monolog/2.10.0.0/xxx.zip,少一层目录,Composer 就找不到包。











