不该随便用 composer global require,因为它将包安装到全局 vendor 目录导致所有项目共享依赖、无法按项目隔离版本、默认不锁定版本易引发崩溃,并存在 path 配置、autoload 冲突、php 版本兼容等多重风险。

为什么 composer global require 不该随便用
它会把包装进全局 Composer vendor 目录(通常是 ~/.composer/vendor/bin/),所有项目共享同一份依赖,一旦某个包升级破坏了 CLI 行为,你没法按项目隔离修复。更麻烦的是,它默认不锁定版本——composer global update 一跑,可能全盘崩掉。
常见错误现象:command not found 即使 composer global require foo/bar 成功;或者某天突然报 Class not found,因为另一个全局包更新后改了 autoloader 规则。
- PATH 必须包含
~/.composer/vendor/bin(macOS/Linux)或%APPDATA%\Composer\vendor\bin(Windows),否则命令根本不可见 - 全局安装的包无法声明
require-dev,测试和开发依赖全得塞进主require - PHP 版本、扩展差异会被忽略——比如你在 PHP 8.2 下全局装了只兼容 7.4 的工具,运行时报错但无提示
如何安全地发布一个可 composer global require 的 CLI 包
核心不是“怎么装”,而是“怎么写”:包必须满足 Composer 对全局二进制的识别规则,且入口脚本要能脱离项目上下文独立运行。
关键点在 composer.json:
-
"bin"字段必须指向一个可执行 PHP 脚本(如"bin/mytool"),且该文件首行要有#!/usr/bin/env php -
"autoload"推荐用"psr-4",避免"files"方式——全局 autoload 是单例,冲突风险高 -
"minimum-stability"建议设为"stable",防止用户无意中拉到 dev 分支的破坏性变更
示例 bin/mytool 开头:
#!/usr/bin/env php <?php require_once __DIR__.'/../vendor/autoload.php'; // 后续逻辑不依赖 getcwd() 或 $_SERVER,用绝对路径或 Composer 自动加载
替代方案:用 phar 打包比全局 require 更可控
如果你只是想让用户一行命令装上 CLI 工具,phar 是更干净的选择——它不污染全局 vendor,不依赖用户 Composer 配置,还能自带 PHP 版本检查。
使用场景:工具功能稳定、依赖不多、不需要频繁更新 composer.lock 级别的细节。
- 用
humbug/phar-builder或原生Phar扩展打包,入口文件需显式调用Phar::mapPhar() - 发布时附带 SHA256 校验值,用户可用
curl -sS https://example.com/mytool.phar | sha256sum验证完整性 - 安装脚本建议用
sudo mv mytool.phar /usr/local/bin/mytool && sudo chmod +x /usr/local/bin/mytool,避免 PATH 冲突
遇到 command not found 先查这三件事
别急着重装,90% 是环境没对齐。
- 运行
composer global config bin-dir --absolute,确认输出路径是否已在$PATH中(Linux/macOS)或%PATH%(Windows) - 检查目标命令文件权限:
ls -l $(composer global config bin-dir --absolute)/mytool,必须有x位 - 如果用了 Zsh 或 Fish,确认 shell 配置文件(如
~/.zshrc)里 reload 了 PATH,而不是只改了当前终端
复杂点在于:全局 bin 目录可能被多个 Composer 版本共用,比如你用 Homebrew 装的 Composer 和手动下载的 phar 版本,composer global 指向的 vendor 根本不同——这种混用几乎必然出问题。










