post-install-cmd 仅在 vendor/ 不存在或为空时执行 composer install 触发,不响应 update 或已有依赖场景;需用 post-update-cmd 实现每次更新后运行,脚本须定义在根 composer.json 的 scripts 字段中。

Post-install-cmd 脚本执行时机和触发条件
Composer 的 post-install-cmd 只在运行 composer install 且 vendor/ 不存在或为空时触发。它不会在 composer update 或已有依赖已安装的情况下执行——这点常被误认为“脚本没生效”,实际是命令用错了。
- 如果想每次更新依赖后都执行(比如生成 autoload map 或清理缓存),改用
post-update-cmd -
post-install-cmd不会因--no-scripts以外的参数跳过,但 CI 环境中若用了--no-dev,而脚本定义在require-dev包里,也可能导致脚本未加载 - 脚本注册必须写在根
composer.json的"scripts"字段下,子包里的定义不生效
在 scripts 中声明 PHP 函数或命令行脚本
scripts 支持三种调用方式:内置命令、自定义 PHP 方法、外部 shell 命令。优先用 PHP 方法,避免跨平台兼容问题(如 Windows 下 rm -rf 失败)。
- 内置命令直接写字符串:
"post-install-cmd": "php artisan optimize:clear"(Laravel 场景) - 自定义 PHP 方法需带命名空间和双冒号:
"post-install-cmd": "App\ComposerScripts::buildAssets",对应类中需是public static方法 - Shell 命令建议加
|| true防止非零退出码中断安装流程,例如:"post-install-cmd": "npm ci && npm run build || true" - 多个脚本用数组形式顺序执行,比用
&&更清晰、更易调试:"post-install-cmd": ["@php scripts/build.php", "chmod +x bin/deploy"]
PHP 脚本里如何安全访问 Composer 运行上下文
纯 PHP 脚本(如 App\ComposerScripts::buildAssets)默认收不到 Composer 的 IO 或 Event 对象。若需要读取配置、判断是否是生产环境,得手动传入或从全局状态提取。
- 推荐方式:通过
Composer\Script\Event参数接收上下文,方法签名必须为public static function buildAssets(Event $event) - 从
$event可拿到$event->getComposer()(项目配置)、$event->getIO()(输出控制)、$event->isDevMode()(区分 --dev/--no-dev) - 不要直接
require 'vendor/autoload.php'—— Composer 已加载自动加载器,重复 require 可能引发 ClassLoader 冲突 - 若脚本需修改文件(如生成 env 文件),路径应基于
getcwd(),而非硬编码./.env;CI 环境工作目录可能不是项目根
常见失败原因和调试技巧
post-install-cmd 报错时 Composer 默认只显示 “Script xxx handling the post-install-cmd event returned with error code 1”,不打印具体错误,排查成本高。
- 加
-v(verbose)参数重跑:composer install -v,能看到完整命令输出和堆栈 - 在 PHP 脚本开头加
error_reporting(E_ALL); ini_set('display_errors', 1);,确保错误不被静默吞掉 - 避免在脚本里调用
exit()或die()—— Composer 期望脚本自然返回,异常应抛出RuntimeException - Windows 用户注意路径分隔符:用
dirname(DIR) . DIRECTORY_SEPARATOR . 'public',别写死/public
Composer 的脚本机制本身轻量,但组合使用时容易混淆 post-install-cmd 和 post-autoload-dump 的边界——后者在 autoloader 重建时触发,更适合影响类加载逻辑的操作,比如注册 classmap 或生成代理类。











