bin字段用于声明项目根目录下可执行文件路径,使Composer在install/update后将其软链接至vendor/bin/;需确保文件存在、有执行权限且含shebang(如#!/usr/bin/env php)。

composer.json 里的 bin 字段到底起什么作用
bin 字段不是用来注册 Laravel Artisan 命令或 Symfony Console 命令的,它只干一件事:把项目根目录下某个可执行文件的路径声明出来,让 composer install 或 composer update 执行后,Composer 自动把它软链接到 vendor/bin/ 目录下。换句话说,它是“告诉 Composer:这个文件我想全局(项目级)可用”。
怎么写 bin 才能让自定义脚本出现在 vendor/bin/
必须满足两个条件:路径存在 + 文件有可执行权限。常见错误是写了 "bin": ["bin/mytool"],但实际 bin/mytool 是个 PHP 脚本却没加 shebang,或者没 chmod +x。
-
bin数组里填的是相对于项目根目录的路径,不是类名或命令名 - 推荐用
#!/usr/bin/env php开头,确保能被直接执行(尤其在 macOS/Linux) - Windows 下依赖
.bat或.cmd包装器,单纯 PHP 脚本不会被识别为可执行 bin - 如果脚本依赖
autoload,记得先运行composer dump-autoload
#!/usr/bin/env php run($argv);
为什么 vendor/bin/mytool 找不到,或者报 “Permission denied”
最常踩的坑不是配置错,而是文件权限和环境不匹配。Composer 不会帮你加执行权限,也不会自动创建 Windows 兼容包装器。
- Linux/macOS:运行
chmod +x bin/mytool后再composer install - Windows:要么用
bin/mytool.bat包装(内容为@php "%~dp0mytool" %*),要么改用composer exec替代 - 如果
vendor/bin/不在你的$PATH里,就只能写全路径调用,比如./vendor/bin/mytool - 某些 CI 环境(如 GitHub Actions)默认不保留文件权限,需显式用
git update-index --chmod=+x bin/mytool提交
比起 bin,什么时候该用 scripts 或 composer exec
bin 适合长期复用、需要被其他工具链调用的 CLI 工具;如果是临时任务、调试命令或不想暴露给终端用户,scripts 更干净。
-
"scripts": {"dev:check": "php scripts/check.php"}→ 运行composer dev:check -
composer exec --list可列出所有已注册 script,但不会生成vendor/bin/文件 -
composer exec mytool能绕过权限问题,但每次都会重新加载 autoloader,性能略低 - 第三方包(如
phpunit、php-cs-fixer)靠bin注册,是因为它们设计为独立 CLI 工具,不是项目内部逻辑
bin,到了 Windows CI 就卡在权限或换行符上。别指望 bin 字段自动帮你做适配。










