bin-dir必须是相对路径,如"bin"或"./tools",不可用绝对路径;需手动创建目录并确保写权限;修改后须清缓存、删vendor并重装依赖才生效;PATH需手动配置才能直接调用命令。

bin-dir 是 Composer 用来决定依赖包 CLI 工具(如 phpunit、phinx)最终链接或复制到哪的配置项,不是“随便改个路径就能用”,它必须是相对路径、需手动创建、且改完不重装就无效。
bin-dir 必须是相对路径,写绝对路径会直接报错
Composer 解析 bin-dir 时,只以项目根目录(即 composer.json 所在处)为基准。哪怕你写 "bin-dir": "/home/user/project/bin" 或 "bin-dir": "C:\myproject\scripts",composer install 会立刻中断并抛出:Invalid bin-dir path。
✅ 正确写法只有这些形式:
-
"bin-dir": "bin"→ 实际生成./bin/ -
"bin-dir": "./tools"→ 实际生成./tools/ -
"bin-dir": "scripts"→ 实际生成./scripts/
⚠️ "bin-dir": "$HOME/bin" 在全局配置中可能展开,但项目级配置里行为不可靠,别用。
改了 composer.json 的 bin-dir,为什么 vendor/bin 还在、新目录却空着?
因为 Composer 不会热更新:只改配置不触发重建逻辑,旧链接不动,新目录也不会自动创建或填充。
要真正切换过去,必须三步一起做:
- 手动创建目标目录:
mkdir -p bin(Windows 用mkdir bin) - 确认有写权限:
test -w bin && echo ok || echo no write - 删掉整个
vendor/(不能只删vendor/bin),再运行composer clear-cache,最后执行composer install
缺任何一步,bin/ 要么不存在,要么没文件,要么权限不足,错误信息可能是模糊的 Could not create bin dir 或静默失败。
脚本生成了,但终端敲 phpunit 还是 command not found
这是最常被忽略的一环:bin-dir 只管“放哪儿”,不管“怎么找”。shell 默认不查 ./bin,也不自动加进 $PATH。
Linux/macOS 下需手动导出:
- 临时生效(当前终端):
export PATH="./bin:$PATH" - 永久生效(推荐):
echo 'export PATH="./bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
Windows 下得把 %CD%in 加进系统或用户环境变量 PATH;另外注意:bin/phpunit 在 Windows 上实际是 bin/phpunit.bat,直接敲 phpunit 可能失败,除非你已把 .bat 加入 PATHEXT。
另一个绕过 PATH 的办法是:composer exec phpunit —— 它会自动定位当前 bin-dir 并执行,但无法替代真实环境变量配置,尤其对 IDE 或 CI 场景。
为什么有些命令没出现在新 bin-dir 里?
不是所有 CLI 工具都走 bin-dir 流程。关键看两点:
- 该包自己的
composer.json是否声明了bin字段(比如"bin": ["phpunit"]) - 你自己的项目是否也声明了
bin字段(如"bin": ["mytool"]),否则你的脚本不会被自动部署过去
像 Laravel 的 artisan、Symfony 的 console 这类入口脚本,通常由框架自己管理,不依赖 Composer 的 bin 机制,所以改 bin-dir 对它们完全无效。
还有更隐蔽的情况:某些插件(如 dealerdirect/phpcodesniffer-composer-installer)会绕过 bin-dir,直接往 vendor/bin 写,这时你看到两个目录都有同名文件,优先级取决于 $PATH 顺序。


















