post-install-cmd 未执行的首要原因是 composer.json 根级未正确定义 "scripts" 对象,键名必须为 "post-install-cmd"(非 post-install 或 post-install-cmds),值需为合法字符串、数组或类方法;路径应以项目根目录为基准,脚本需显式引入 autoload.php 并正确处理退出码。

post-install-cmd 脚本没执行?先确认它真被注册了
Composer 不会自动运行任何脚本,除非你在 composer.json 里明确声明。很多人改完脚本就跑 composer install,发现什么都没发生——根本原因是 "scripts" 段没配,或者键名拼错了。
常见错误现象:post-install-cmd 写成 post-install 或 post-install-cmds;脚本值是字符串但没加引号导致 JSON 解析失败;整个 "scripts" 块被放在了错误层级(比如塞进了 "autoload" 里)。
- 必须在
composer.json的根级定义"scripts"对象 - 键名严格为
"post-install-cmd"(注意是cmd,不是command) - 值可以是字符串(如
"php build.php")、数组(按顺序执行多条命令),或指向类方法的数组格式["MyScript", "run"] - 修改后无需手动刷新缓存,但若之前已安装过依赖,建议先删掉
vendor/和composer.lock再重装以确保钩子生效
脚本里调用 PHP 文件,路径容易错在哪
在 post-install-cmd 里写 "php scripts/build.php" 很常见,但实际执行时当前工作目录是项目根目录,不是 vendor/bin 或脚本所在目录——所以相对路径一写错,直接报 Could not open input file。
使用场景:你想生成配置、清理缓存、初始化数据库结构,这些操作都依赖脚本文件存在且可读。
- 推荐用项目根目录为基准写路径,比如
"php ./scripts/deploy.php"(开头加./更安全) - 避免用
__DIR__或dirname(__FILE__)在被调用的 PHP 脚本里做路径推导——因为 Composer 是用proc_open启动新进程,__DIR__指向的是执行时的 PHP 解释器位置,不是你的脚本位置 - 如果脚本需要加载 Composer 自动加载机制(比如用到
vendor/autoload.php),务必在脚本开头显式引入:require __DIR__ . '/vendor/autoload.php'; - Windows 下注意路径分隔符,用
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.php'比硬写"\config.php"更稳妥
post-install-cmd 和 post-update-cmd 的行为差异
这两个钩子触发时机不同,但很多人混用,结果在 CI 环境或团队协作中出现意料外的行为。关键区别不在“安装”还是“更新”,而在于是否检测到 composer.lock 变更。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
性能 / 兼容性影响:如果脚本耗时较长(比如生成前端资源),误用 post-update-cmd 会导致每次 composer update 都执行,而 post-install-cmd 只在 composer install 且 lock 文件存在时运行一次——更适合部署场景。
-
post-install-cmd:当composer install执行且composer.lock存在时触发(即从 lock 安装依赖) -
post-update-cmd:当composer update执行并成功更新composer.lock后触发 - 如果项目没有
composer.lock,composer install行为等价于composer update,此时也会触发post-update-cmd,而不是post-install-cmd - CI 流水线中建议优先用
post-install-cmd,避免因开发者本地执行update导致构建环境反复执行构建脚本
脚本出错时 Composer 默认不中断安装
默认情况下,哪怕你的 post-install-cmd 脚本执行失败(比如返回非零退出码),Composer 仍会显示 Installing dependencies... 成功,并继续后续流程。这会让问题藏得更深——你以为部署完了,其实缓存没清、配置没写入。
容易踩的坑:脚本里用了 file_put_contents 但目标目录不可写,却没检查返回值;调用了外部命令但没加 || exit 1;PHP 报错被 @ 抑制后静默失败。
- 所有 shell 命令末尾加上
&&连接或|| exit 1,例如:"php scripts/init.php && chmod -R 755 storage/" - PHP 脚本结尾显式调用
exit(0)成功,exit(1)失败,不要依赖隐式返回 - 在 CI 中建议加
--no-interaction --no-ansi参数运行 Composer,避免颜色控制符干扰日志解析 - 调试阶段可在脚本开头加
echo "Running post-install-cmd...";并配合composer install -v查看是否真的进入该钩子
钩子脚本的本质是独立进程,和 Composer 主流程只有退出码这一种通信方式。别指望它能共享变量或临时状态,也别在脚本里试图修改 composer.json 再触发下一轮安装——那只会陷入循环。

















