composer.json 必须放在 php 代码所在子目录(如 backend/)下,而非仓库根目录;该目录需包含所有 php 源码、composer.json 和 vendor/,autoload 路径以该目录为基准,ci 中需先 cd 进入该目录再执行 composer install。

composer.json 放在哪:多语言项目里 PHP 依赖的归属问题
PHP 依赖必须由 composer.json 驱动,而这个文件只能放在它实际要安装依赖的目录下——不是根目录,也不是随便一个子目录。多语言项目(比如 Python + PHP + JS 混合)常误把 composer.json 放在仓库根目录,结果导致 vendor/ 和 PHP 源码混在一起,CI 构建时被其他语言工具误扫、Git 忽略规则冲突、部署路径错乱。
- 推荐结构:PHP 代码和
composer.json一起放在独立子目录(如src/php/或backend/),该目录下执行所有composer install -
composer.json中的"autoload"路径需以该子目录为基准,不能写成"src/"(除非 src 就在当前目录) - 根目录的
.gitignore要明确忽略backend/vendor/,而非笼统的vendor/,避免影响其他语言的vendor/(如 Go 的vendor/)
autoload 配置踩坑:跨目录加载 PHP 类失败的常见原因
多语言项目中 PHP 模块常被其他部分调用(比如 CLI 工具、API 网关),但 autoload 写错会导致 Class not found,尤其当源码不在 composer.json 所在目录下时。
- 别用
"psr-4": {"App\": "src/"}这种相对路径,除非src/真在composer.json同级;更安全的是用"psr-4": {"App\": "src/php/src/"} - 如果 PHP 代码分散在多个子目录(如
lib/和app/),用多个 autoload 映射,不要合并成一个路径 - 运行
composer dump-autoload -o后检查生成的vendor/autoload.php是否真能 require 到你的类——最简单的验证是进backend/目录跑php -r "require 'vendor/autoload.php'; var_dump(class_exists('App\Foo'));"
CI/CD 中 composer install 的路径隔离要点
GitHub Actions、GitLab CI 默认工作目录是仓库根目录,直接跑 composer install 会试图在根目录找 composer.json,失败或装错位置。
- CI 脚本里必须先
cd backend/(或对应 PHP 子目录)再执行composer install --no-dev - 如果使用 Docker 构建,
Dockerfile中的COPY . /app后,要WORKDIR /app/backend,而不是在/app下运行 composer - 避免用
COMPOSER_HOME或--working-dir临时指定路径——容易漏掉 autoload 生成逻辑,且不同 Composer 版本行为不一致
vendor 目录能否共用?为什么不要共享 vendor 到其他语言项目
有人想把 vendor/ 提到根目录供多个 PHP 子模块复用,或者让 Python 脚本去调用 vendor/bin/xxx ——这几乎必然出问题。
立即学习“PHP免费学习笔记(深入)”;
-
vendor/是绑定具体composer.json和锁文件的,跨项目复用会破坏依赖一致性,composer update行为不可控 - PHP 的
bin工具(如phpunit、php-cs-fixer)依赖vendor/autoload.php的相对位置,挪动后脚本头部的#!/usr/bin/env php后续逻辑大概率失效 - 真正需要跨语言调用 PHP 工具?用完整路径调用,例如
php backend/vendor/bin/php-cs-fixer fix,而不是把backend/vendor/bin加进$PATH
多语言项目里,PHP 的边界感要强:它的依赖、自动加载、构建路径,都得在自己那个子目录里闭环。越想“共享”,越容易在某个深夜收到 CI 失败通知,而错误日志只显示 Class 'MonologLogger' not found——其实只是 autoload 没从对的地方加载。











