vendor/bin 是 Composer 自动创建的目录,用于存放依赖包通过 composer.json 中 "bin" 字段声明的可执行脚本,安装时软链接(Linux/macOS)或生成 .bat(Windows)至该目录,实现项目级 CLI 工具版本隔离。

Composer 的 vendor/bin 目录不是“放脚本的地方”那么简单,它是 PHP 项目实现 CLI 工具版本隔离的核心机制——每个项目用自己依赖的工具版本,互不干扰。
vendor/bin 是怎么生成的?
它完全由 Composer 自动创建和维护,前提是所安装的包在自己的 composer.json 中声明了 bin 字段。比如 phpunit/phpunit 包里有:
"bin": ["phpunit"]
当你运行 composer require --dev phpunit/phpunit,Composer 就会把该包下的 phpunit 文件(路径通常为 vendor/phpunit/phpunit/phpunit)软链接到 vendor/bin/phpunit(Linux/macOS)或生成对应的 .bat 包装脚本(Windows)。
常见误判:
-
vendor/bin不是手动建的,也不该提交进 Git;删掉后运行composer install会自动重建 - 没出现在
vendor/bin的工具,大概率是它所属的包根本没写bin字段(如monolog/monolog) - 脚本文件名必须与
bin字段值**完全一致**,不自动补.php,不支持通配符
为什么全局安装后命令还是找不到?
因为 Composer 从不修改系统 PATH。全局安装(composer global require phpunit/phpunit)生成的可执行文件实际放在:
- Linux/macOS:
~/.composer/vendor/bin/ - Windows:
%APPDATA%\Composer\vendor\bin
但这些路径不在默认 PATH 里。验证方式:
- macOS/Linux:运行
echo $PATH,看输出是否含~/.composer/vendor/bin - Windows:运行
echo %PATH%,确认含对应路径
修复方法:
- macOS/Linux:在
~/.zshrc或~/.bashrc末尾加export PATH="$HOME/.composer/vendor/bin:$PATH",再运行source ~/.zshrc - Windows:系统属性 → 高级 → 环境变量 → 用户变量中编辑
PATH,新增一行粘贴完整路径
改完必须新开终端,旧终端不会刷新 PATH。
如何安全地调用 vendor/bin 下的命令?
直接敲 phpunit 看似方便,但隐含风险:它依赖你是否把 vendor/bin 或全局 bin 目录加入了 PATH,且容易和系统其他同名命令冲突。更可靠的方式有三种:
- 显式路径调用:
./vendor/bin/phpunit tests/—— 最稳定,CI/CD 必选 - 用
composer exec:composer exec phpunit tests/—— Composer 自动定位、透传参数、兼容 Windows.bat,适合多环境 - 封装进
composer.json的scripts:"test": "phpunit",然后运行composer test—— 对团队友好,隐藏路径细节
注意:composer exec 不会触发 composer.json 中定义的 scripts,它只代理执行 vendor/bin 下的二进制文件。
自定义 bin-dir 后要注意什么?
你可以通过 composer.json 的 config.bin-dir 改变位置,比如设为 "bin-dir": "tools"。但这只是改了链接存放地,不是魔法开关:
- 改完必须运行
composer install或composer update,否则新目录为空,旧vendor/bin还在 - 新路径(如
tools)不会自动加入PATH,你要手动加,否则命令仍不可见 - Windows 下生成的是
tools/phpunit.bat,不是可执行文件,某些 shell 补全可能识别不了 - 多个包声明同名
bin(如都叫foo),后安装的会覆盖前一个,无提示
真正容易被忽略的是:bin-dir 的变更对已运行的终端进程完全无效,PATH 没更新、链接没重建、.bat 没生成——三者缺一,命令就“消失”。别猜,用 ls -l vendor/bin 或 dir tools 看真实文件,再用 which phpunit 或 where phpunit 查找路径,比反复重装 Composer 实在得多。











