全局命令报“command not found”本质是path未包含可执行文件路径,需手动将对应bin目录(如~/.composer/vendor/bin或%appdata%\composer\vendor\bin)加入系统path并重启终端验证。

全局安装的命令为啥敲了报 command not found
根本不是没装成功,是系统压根没在 PATH 里找那个可执行文件。Composer 全局安装的二进制(比如 laravel、php-cs-fixer)默认放在:~/.composer/vendor/bin(Linux/macOS)或 %APPDATA%\Composer\vendor\bin(Windows),但这个路径不在系统默认 PATH 中。
解决办法只有一步:把对应路径加进 PATH,然后重启终端(不是关掉重开,是新建一个终端进程)。
- Linux/macOS:在
~/.zshrc或~/.bashrc末尾加export PATH="$HOME/.composer/vendor/bin:$PATH",再运行source ~/.zshrc - Windows:打开「系统属性 → 高级 → 环境变量」,在「用户变量」的
PATH里新增%APPDATA%\Composer\vendor\bin - 验证是否生效:
echo $PATH(macOS/Linux)或echo %PATH%(Windows),确认输出含目标路径;再试which laravel或where php-cs-fixer
项目里用 composer require 装了 phpunit,为啥不能直接敲 phpunit
因为它的可执行文件只存在于当前项目的 vendor/bin/phpunit,没进系统 PATH,这和“是否装对”无关,是 Composer 的隔离设计——项目依赖必须私有化。
正确调用方式只有两个:
- Linux/macOS:
./vendor/bin/phpunit - Windows:
vendor\bin\phpunit - 更省事的办法:在
composer.json的scripts字段里加一条"test": "php vendor/bin/phpunit",之后直接运行composer test
别手动给 vendor/bin/phpunit 创建全局软链——CI 流水线会挂,同事拉代码也跑不起来。
哪些包该全局装,哪些死都不能全局装
判断标准不是“它是不是命令行工具”,而是“它参不参与项目运行逻辑”。一句话:工具装全局,依赖装项目。
- ✅ 推荐全局:
laravel/installer、friendsofphp/php-cs-fixer、phpstan/phpstan——它们只在你敲命令时起作用,不被autoload加载,不进生产环境 - ✅ 必须项目内:
guzzlehttp/guzzle、monolog/monolog、symfony/console——这些会被你的代码new或use,必须写进composer.json,必须生成composer.lock,必须上生产 - ⚠️ 特别注意:
phpunit/phpunit表面是工具,但很多项目在autoload-dev里引用它,phpunit.xml也可能依赖特定版本,所以更推荐项目内装 - ❌ 绝对禁止全局:
doctrine/dbal、laravel/framework——等于废掉composer.lock,部署时版本错乱,错误信息会指向你完全没装过的类
全局和项目共存时 autoload 冲突怎么破
比如全局装了 php-cs-fixer v3.20,项目里又 require 了 v3.12,执行时突然报 Class 'Symfony\Component\Finder\Finder' 找不到——这不是类名写错了,是 autoloader 加载了错误版本的依赖。
根本原因是 Composer 的全局 autoloader 和项目 autoloader 混用了。解决方案很直接:
- 全局工具尽量选不带运行时依赖的纯 CLI 包(查
composer.json的require字段,越空越好) - 项目里如果要用同名工具,一律走
composer require --dev,并确保vendor/autoload.php不被全局脚本加载 - CI 流水线中禁用全局安装,所有工具都走项目内
composer install+scripts调用,避免环境漂移
最常被忽略的一点:全局安装后从不更新,但项目里用了新版特性,结果本地能跑、CI 报错——因为全局版本太老,而你忘了它还在 PATH 里占着位。











