可通过composer_home配合全局config.json设置共享vendor路径:先设composer_home指向自定义目录,再在其下config.json中配置"vendor-dir";项目级composer.json不支持vendor-dir,仅全局/系统级config生效。

如何用 COMPOSER_HOME + composer.json 配置全局 vendor 路径
不能直接改 vendor 目录位置,但可以绕过它——Composer 本身不支持 per-project 的 vendor 重定向,但支持通过环境变量把整个依赖生态挪到别处。核心是让所有项目共用一个集中安装路径,而不是每个项目都建 vendor。
关键操作分两步:先设 COMPOSER_HOME 指向自定义根目录,再在该目录下放一个全局 config.json,指定 vendor-dir:
-
export COMPOSER_HOME="/path/to/my-composer-home(Linux/macOS)或set COMPOSER_HOME=C:\my-composer-home(Windows) - 在
/path/to/my-composer-home/config.json中写入:{ "config": { "vendor-dir": "/opt/shared-vendor" } } - 之后所有
composer install都会把包装进/opt/shared-vendor,而非当前项目的vendor
⚠️ 注意:COMPOSER_HOME 影响的是 Composer 自身配置、缓存、全局命令的存放位置,但它配合 config.json 才能真正接管 vendor-dir;单独改 COMPOSER_HOME 不会移动 vendor。
为什么 vendor-dir 放在 config.json 里才生效,而不是 composer.json?
因为 vendor-dir 是 Composer 的「运行时配置项」,只在全局或系统级配置中被读取,composer.json 中声明的 config 字段会被忽略——这是 Composer 的硬性限制,不是 bug。
常见错误现象:"config": { "vendor-dir": "lib" } 写在项目 composer.json 里,执行 composer install 后还是生成 vendor 目录,毫无反应。
- 只有
COMPOSER_HOME/config.json或/etc/composer/config.json(系统级)里的vendor-dir才会被尊重 - 项目级
composer.json可以设bin-dir、process-timeout等,但vendor-dir是明确被排除的 - 如果多个配置源同时存在,优先级为:命令行
-d> 项目composer.json(不含vendor-dir)>COMPOSER_HOME/config.json> 系统配置
使用 symlinks 替代配置:当必须保留项目内 vendor 名称时
有些部署工具或 IDE 强依赖 vendor 这个目录名(比如某些 PHPStan 配置、Xdebug 路径映射),此时不能真删掉 vendor,但可以把它变成指向统一路径的软链。
做法简单直接:
- 先在某处创建共享目录:
mkdir -p /srv/php-packages - 用
composer install --no-scripts --no-plugins把依赖装进去(避免触发 autoload 生成等副作用) - 删掉项目里的
vendor,执行:ln -sf /srv/php-packages vendor - 再运行
composer dump-autoload(注意:必须在项目根目录下运行,否则 autoload.php 会写错路径)
⚠️ 容易踩的坑:composer dump-autoload 生成的 vendor/autoload.php 会硬编码真实路径,所以 symlink 本身没问题,但一旦你换机器或改路径,就得重新 dump;另外,composer update 会尝试写入 symlink 目标,若权限不对会失败。
多项目共享 vendor 的实际兼容性风险
看起来省空间又整洁,但 PHP 生态里极少有人这么干,原因很实在:
- 不同项目可能依赖同一包的不同版本(如
monolog/monologv2.9 和 v3.5),共享vendor会导致冲突或加载错版本 -
composer install默认行为是根据composer.lock精确还原,而共享目录无法同时满足多个 lock 文件的版本约束 - 某些包含
install-path或scripts(如phpunit的二进制文件生成),会在共享目录里互相覆盖 - PHP 的
include_path和自动加载器(ClassLoader)都基于文件系统路径,跨项目复用 vendor 本质是破坏了 Composer 的隔离契约
真正安全的做法,是仅对「完全相同依赖栈」的同构项目(比如几十个 Laravel 微服务镜像构建阶段)做缓存加速,而不是运行时共享。日常开发,老老实实留着每个项目的 vendor 最省心。










