composer 不支持跨项目自动同步依赖,因每个 composer.json 是独立契约,lock 文件仅作用于当前项目;复用依赖靠规范而非工具,生产环境必须使用私有 packagist 或 satis 发布语义化版本包。

Composer 不支持跨项目自动同步依赖
多个项目之间无法靠 composer update 自动联动升级,这是设计使然,不是配置没配对。它没有“依赖中心化控制台”,每个 composer.json 是独立的契约,composer.lock 也只对当前项目生效。
常见错误现象:
— 在项目 A 更新了 myorg/utils 到 1.2.0,项目 B 还是 1.1.5,结果本地调用行为不一致;
— 有人尝试把所有项目的 vendor 指向同一个目录,结果跑出 Class not found 或 autoload 路径错乱——因为 vendor/autoload.php 硬编码了相对路径,根本不能共享。
- 真正能复用的只有缓存:Composer 默认用
~/.composer/cache,不用额外配置,但确保所有项目走的是同一缓存路径(默认就是) - 想让多个项目“用同一套依赖版本”,靠的是人+规范,不是工具:统一写
"laravel/framework": "^10.40"而不是"*",再配合脚本批量检查 - 不要试图用
composer global require来装业务依赖——它只适合 CLI 工具,比如phpunit/phpunit或phpstan/phpstan
本地开发时快速联调多个仓库
微服务或模块化架构下,user-service 要调 user-sdk,但后者还没发版,又不想手动 git clone + cp,这时用 path 类型仓库最轻量。
实操建议:
— 在 user-service/composer.json 的 repositories 里加一段:
{
"repositories": [
{
"type": "path",
"url": "../user-sdk"
}
],
"require": {
"myorg/user-sdk": "dev-main"
}
}
— 运行 composer install,Composer 就会软链接 ../user-sdk 到 vendor/myorg/user-sdk,改 SDK 代码立刻生效。
- 必须确保
user-sdk目录下有合法的composer.json,且含name字段(如"myorg/user-sdk"),否则报Could not find package -
dev-main这种写法依赖 Git 分支名,如果分支叫develop,就得写dev-develop;tag 版本如1.0.0则无需dev-前缀 - 上线前务必删掉
path配置,换成私有仓库地址,并提交composer.lock,否则 CI 构建失败
生产环境必须用私有 Packagist 或 Satis
用 path 只能本地跑通,CI/CD 流水线、Docker 构建、多机部署全会断——因为路径不存在。生产唯一可靠的方式,是把公共组件发布成带语义化版本的包,走标准 Composer 流程。
推荐选型逻辑:
— 小团队、无运维资源:用 satis,静态生成 JSON 索引,搭在 Nginx 上就行,配合 GitHub Actions 自动 rebuild;
— 中大型团队、要权限/审计/API 集成:上 Private Packagist 或 Artifactory,支持代理 public 包、细粒度 token 控制。
- 发布前确认
user-sdk的composer.json里写了"type": "library"和完整autoload,否则其他项目dump-autoload时扫不到类 - 所有项目统一加一行配置:
composer config --global repos.packagist.org false,再添加私有源,避免意外拉到 public 上同名但不可信的包 - 禁止在生产环境运行
composer update;必须靠composer install --no-dev+ 提交的composer.lock保证可重现
要不要上 Monorepo?先看耦合度
Monorepo 不是银弹,它解决的是“高度协同演进”的问题,比如一个 UI 组件库和用它的管理后台,改 API 就得一起测。如果只是几个独立微服务,硬塞进一个仓库只会让 git blame、PR 审查、CI 时间全变重。
判断信号:
— 是否经常出现“改 A 服务必须同步改 B 服务才能过测试”?
— 是否多个项目共用同一套 CI 配置、部署流程、版本发布节奏?
— 是否已有工具链支持(如 turborepo、nx)?
- 若决定上,根目录
composer.json只配repositories和脚本,不写业务require;每个子包(packages/*)保持独立composer.json和name - 别用已废弃的
composer-merge-plugin,它不兼容 Composer 2.2+;现代做法是靠pathrepo +composer install --prefer-source实现软链接 - Monorepo 的最大隐性成本不是技术,是协作习惯——需要所有人接受“跨包 PR”和“统一版本号”规则
composer.json 里偷偷写 *、上线前记得删 path 配置——这些细节比工具本身更决定成败。










