Composer默认只读取当前工作目录的composer.json,子目录中同名文件被忽略;需用--working-dir指定路径执行安装,且子包类要手动在根目录autoload中映射并dump-autoload。

Composer 不会自动读取或执行子目录里的 composer.json,除非你显式告诉它“去那里工作”——这是绝大多数人踩坑的起点。
子目录的 composer.json 默认被完全忽略
你在 packages/foo/composer.json 里写得再完整,只要没切到那个目录或没用 --working-dir,Composer 就当它不存在。它只认当前工作目录下的 composer.json,其他同名文件一律跳过。
- 常见错误现象:
Class not found、require_once(): Failed opening required 'vendor/autoload.php',其实是因为类没注册进自动加载,而根源是子包根本没被 Composer “看见” - 不是“不支持”,而是“不自动发现”:Composer 没有扫描子目录的机制,也没有 monorepo 原生模式
- 如果你在根目录运行
composer install,packages/foo/vendor/不会生成,packages/foo/composer.json的require一条都不会装
composer install --working-dir=packages/foo 是最直接的解法
不用 cd,不改环境,一行命令就能让 Composer 在指定路径下执行完整流程:读配置、解析依赖、装包、生成 vendor/、写 autoload。
- 路径必须是相对当前目录的,不能用
~或$HOME;--working-dir=../foo也不行,只能是packages/foo这种向下展开的路径 - 执行后,依赖会落到
packages/foo/vendor/,和根目录的vendor/完全隔离,互不影响 - CI 脚本里推荐统一用这个参数,避免
cd后忘记cd -导致后续命令出错 - 如果子包有自定义脚本(如
post-install-cmd),它们会在该上下文中执行——但仅限于这个子包自己的composer.json
子包要被主项目加载,必须手动注册 PSR-4 并 dump-autoload
即使子包已安装成功,它的类也不会自动出现在主项目的自动加载器里。你得在根目录的 composer.json 中声明映射,并重新生成自动加载文件。
- 在根目录
composer.json的"autoload"下加 PSR-4 映射,例如:"Foo\": "packages/foo/src/" - 然后在根目录运行
composer dump-autoload——注意不是在packages/foo/里运行 - 如果不做这步,
new FooSomeClass()依然会报错;composer install --working-dir不会帮你触发这一步 - 子包若含测试类或私有工具类,可额外在
"autoload-dev"中补充映射,比如"Foo\Tests\": "packages/foo/tests/"
本地子包想被 require,必须配 repositories + require + @dev
仅仅把子包放在 packages/ 下,主项目还是无法 composer require foo/bar。你需要让它“可发现、可安装、可锁定版本”。
- 在根目录
composer.json的根层级加"repositories",类型必须是"path",url 是相对于该文件的路径,例如:"url": "packages/foo" - 子包自己的
composer.json必须有合法"name"(如"myorg/foo")和"version"或"@dev"标签 - 然后在根目录运行
composer require myorg/foo *@dev,否则 Composer 会跳过 path 匹配 - 开发时建议加
"options": {"symlink": true},这样改子包代码无需反复install;但上线前必须删掉repositories块,否则部署失败
最易被忽略的一点:多个 vendor/ 目录共存时,vendor/bin 二进制文件会打架——不同目录下的 phpunit 可能版本不同,而 shell 只认 PATH 里第一个,调用时根本意识不到自己跑错了。


















