composer如何为CLI工具创建全局安装包?(composer global require风险提示)

6次阅读

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

composer如何为CLI工具创建全局安装包?(composer global require风险提示)

为什么 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/binmacos/linux)或 %APPDATA%Composervendorbinwindows),否则命令根本不可见
  • 全局安装的包无法声明 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 根本不同——这种混用几乎必然出问题。

text=ZqhQzanResources