优先使用 ./vendor/bin/xxx 显式调用,因 PATH 查找顺序使全局 ~/.composer/vendor/bin 通常排在项目 ./vendor/bin 前,导致命令被全局版本覆盖;验证需用 which、head 和 composer show 对比路径与版本;推荐用 composer scripts 或 phive 替代全局 Composer 工具。

全局 Composer 包和项目 vendor/bin 下同名命令冲突时,优先用 ./vendor/bin/xxx 显式调用,而不是依赖 PATH 查找顺序。
为什么全局 bin 会覆盖项目 bin?
系统执行命令时按 PATH 从左到右查找可执行文件。默认配置下,~/.composer/vendor/bin(或 Windows 的 %APPDATA%\Composer\vendor\bin)通常排在项目 ./vendor/bin 前面——所以敲 phpunit 实际运行的是全局版本,哪怕项目里装了更新的 phpunit/phpunit。
常见错误现象:
- 运行
phpstan报Class not found,但./vendor/bin/phpstan正常 -
which phpstan指向~/.composer/vendor/bin/phpstan,而该文件头是require __DIR__.'/../vendor/autoload.php',加载的是全局 autoloader - CI 脚本中未写全路径,导致本地能过、CI 失败
如何验证当前生效的是哪个版本?
别猜,用命令确认:
- 查命令位置:
which phpunit或where phpunit(Windows) - 看脚本内容:
head -n 5 $(which phpunit),确认它 require 的是不是全局autoload.php - 查项目实际装的版本:
composer show phpunit/phpunit,再对比./vendor/bin/phpunit --version
如果三者不一致,就是冲突已发生。注意:IDE(如 PHPStorm)默认也走 PATH,需手动配置 CLI interpreter 使用项目 vendor/autoload.php。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
长期方案:让项目 bin 优先且稳定生效
临时绕过很简单:./vendor/bin/php-cs-fixer;但日常开发需要自动化。可行做法包括:
- 在项目根目录加
Makefile,定义fix:目标调用./vendor/bin/php-cs-fixer - 在
composer.json的scripts字段里写"cs-fix": "php-cs-fixer fix",然后用composer cs-fix—— Composer 会自动优先使用项目vendor/bin下的二进制 - 在 shell 配置(如
~/.zshrc)里加export PATH="./vendor/bin:$PATH",但仅对当前 shell 有效,且多项目并行时容易串味 - 彻底弃用全局工具:运行
composer global remove phpunit/phpunit laravel/installer,改用项目级安装 +composer require --dev
关键点在于:全局 composer global 不受项目 composer.lock 约束,composer global update 可能悄悄重装整个 ~/.composer/vendor,导致某个项目依赖的底层包(如 symfony/console)被升级后与项目 lock 文件不兼容。
替代方案:用 phive 管理全局 PHAR 工具
如果确实需要跨项目使用的 CLI 工具(如 phpstan、psalm、infection),phive 是比 composer global 更干净的选择:
-
phive install phpstan会下载签名 PHAR 到~/.phive/phars/,不带任何 PHP 依赖树 - 通过 symlink 放入
~/.local/bin并加入PATH,完全隔离于 Composer autoload 机制 - 不会和项目
vendor/里的类产生任何加载冲突
复杂点在于:PHAR 工具无法像 Composer 包那样自动注入项目配置(比如 phpstan.neon 路径仍需手动指定),但换来的是确定性——你永远知道跑的是哪个版本,且它绝不会污染项目自动加载器。

















