Composer 默认只识别当前工作目录的 composer.json,子目录需用 --working-dir 指定或 cd 进入执行;根项目需在 autoload 中配置 PSR-4 映射并 dump-autoload 才能加载子包类。

Composer 默认不识别子目录里的 composer.json
你把一个 composer.json 放进 packages/foo/,直接在项目根目录跑 composer install,它完全无视——因为 Composer 只认当前工作目录下的 composer.json。这不是 bug,是设计:它默认只管“单项目”,不是为 Monorepo 原生设计的。
想让子目录的 composer.json 生效,必须显式切换到那个目录下执行命令:
- 进入子目录:
cd packages/foo - 再运行:
composer install或composer update - 依赖会装进
packages/foo/vendor/,和根目录的vendor/完全隔离
用 composer install --working-dir 避免 cd 切目录
频繁 cd 很烦,尤其写 CI 脚本或批量操作时。--working-dir 是官方支持的替代方案,它告诉 Composer “假装我在那个目录里运行”:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
composer install --working-dir=packages/foocomposer update --working-dir=packages/bar --with-all-dependencies- 注意路径是相对当前目录的,不能用
~或环境变量,得写死或用 shell 变量展开 - 这个参数从 Composer 2.0 开始稳定支持,1.x 不可用
子目录包怎么被根项目识别并加载?
光有子目录的 composer.json 和独立 vendor/ 没用——根项目的代码还是 require 不到 packages/foo 里的类。必须让自动加载器知道它的存在:
- 在根目录的
composer.json的"autoload"或"autoload-dev"里加 PSR-4 映射:"autoload": { "psr-4": { "Foo\": "packages/foo/src/" } } - 然后运行
composer dump-autoload(根目录下),不是子目录里 - 如果子包要发布到 Packagist,还得在它的
composer.json中设"name"(如"myorg/foo"),并在根目录的composer.json中用"repositories"指向本地路径:"repositories": [ { "type": "path", "url": "./packages/foo" } ]再composer require myorg/foo
常见坑:vendor/bin 冲突、脚本执行错位、缓存污染
多个 vendor/ 目录共存时,最容易出这三类问题:
-
vendor/bin不统一:根目录和子目录各自生成二进制文件(比如phpunit),但 shell 默认只找当前PATH里的第一个,容易调错版本 - 脚本执行位置敏感:在根目录写
"scripts": {"test": "phpunit"},实际执行时如果没切到子目录,就找不到子包的测试配置 - Composer 缓存复用混乱:不同目录共用全局缓存,但
composer.lock内容不同,偶尔导致install结果不一致;可临时用--no-cache排查
真正麻烦的不是怎么跑命令,而是维护多份 composer.lock 时,版本漂移、PHP 版本约束冲突、开发和 CI 环境不一致——这些得靠明确的约定和自动化校验,而不是靠某个 flag 解决。

















