post-update-cmd必须嵌套在composer.json的"scripts"对象内,支持命令字符串或PHP回调两种写法;常见错误包括键名拼错、JSON格式错误、路径不明确、权限限制及未配置autoload导致类找不到。

Composer 的 post-update-cmd 脚本会在 composer update 执行完成后触发,但默认不会自动运行你写的清理逻辑——必须显式注册、且注意执行时机和环境差异。
怎么在 composer.json 里正确注册 post-update-cmd
它不是写在 "scripts" 外面的独立字段,而是必须嵌套在 "scripts" 对象内。常见错误是拼错键名(比如写成 post-update 或 post-update-command),或漏掉引号导致 JSON 解析失败。
支持两种写法:
- 直接写命令字符串(适合单行 shell 命令)
- 写 PHP 回调函数(需配合
"php"可执行路径或自动加载)
{
"scripts": {
"post-update-cmd": [
"@php -r \"file_put_contents('update-timestamp.txt', date('c'));\"",
"rm -rf var/cache/*"
]
}
}
为什么你的清理脚本没执行?常见原因
post-update-cmd 不会运行,多数是因为:
- 当前目录下没有有效的
composer.json(比如你在子目录执行composer update,但配置在父目录) - 脚本中用了相对路径(如
rm -rf cache/),而 Composer 是在项目根目录执行命令,但当前工作目录可能不是根目录 —— 推荐一律用./cache/或${PWD}/cache/ - 权限问题:某些系统禁止在脚本中执行
rm -rf(尤其 macOS Catalina+ 或 WSL2 的文件系统挂载限制) - 脚本返回非零退出码,Composer 默认会中断后续脚本(可用
"@php -r 'exit(0);'"强制兜底)
PHP 回调方式更适合复杂清理逻辑
当你要判断缓存是否启用、检查 Symfony 环境、或调用框架的 CacheWarmer 时,纯 shell 很难处理。这时应写一个可调用的 PHP 方法,并确保类已自动加载。
例如,在 src/ComposerScripts.php 中定义:
getIO();
$io->write('Clearing cache...');
exec('php bin/console cache:clear --no-warmup --env=prod 2>&1', $output, $return);
if ($return !== 0) {
$io->writeError('Cache clear failed ');
}
}
}
然后在 composer.json 中注册:
{
"autoload": {
"psr-4": { "App\\Composer\\": "src/Composer/" }
},
"scripts": {
"post-update-cmd": [
"App\\Composer\\Scripts::clearCache"
]
}
}
注意:autoload 必须存在且能被 Composer 识别,否则回调会报 Class not found。
post-update-cmd 和 post-install-cmd 的关键区别
两者都属于 Composer 生命周期钩子,但触发条件不同:
-
post-update-cmd:仅在composer update时触发(包括composer update vendor/package) -
post-install-cmd:在composer install时触发,也包括首次composer install或composer update后锁文件变更时的重装 - 如果你希望「只要依赖变了就清缓存」,建议两个钩子都注册相同逻辑,或统一用
post-autoload-dump(它在 autoloader 重建后运行,更贴近“代码结构已更新”的语义)
真正容易被忽略的是:Composer 8+ 默认启用插件安全模式,自定义脚本若含危险操作(如 exec()、shell_exec()),可能被静默跳过 —— 检查输出里是否有 Skipping plugin execution due to security policy 提示。









