composer scripts 是轻量级生命周期响应机制,仅适合依赖就位后的确定性操作;post-install-cmd 仅在 vendor 为空或 lock 过期时触发,post-update-cmd 每次 update 必触发,post-autoload-dump 每次 autoloader 更新必执行;应避免用 scripts 做部署,而用独立脚本由 ci/cd 调用。

Composer 的 scripts 钩子不是自动化治理工具,而是轻量级生命周期响应机制;它只适合做“依赖就位后立刻执行的确定性操作”,比如生成 autoload、复制模板配置、清理 dev-only 文件——超出这个范围,就是拿螺丝刀当电钻用。
post-install-cmd 和 post-update-cmd 触发条件完全不同
这两个钩子常被混用,但实际行为差异极大,直接决定自动化是否“看似配了,实则没跑”:
-
post-install-cmd仅在vendor/为空,或composer.lock不存在/过期需重生成时触发。已有完整vendor和匹配的 lock 文件,再跑composer install就静默跳过 -
post-update-cmd只要执行composer update(包括composer require xxx)就一定触发,哪怕只更新一个 patch 版本 - CI 流水线中反复执行
composer install --no-dev,post-install-cmd很可能一次都不执行;而post-update-cmd在每次依赖变更时稳定触发 - 验证是否真触发?加
-v参数:composer install -v,看输出里有没有Executing script行
post-autoload-dump 是最稳定的“每次必跑”钩子
如果你需要“只要 autoloader 变了就得执行”,post-autoload-dump 是唯一靠谱选择——它在每次 vendor/autoload.php 生成或更新后必然触发,覆盖 install、update、甚至手动 composer dump-autoload 场景:
- 适合做代码生成、静态分析入口、配置注入等“与 autoload 状态强绑定”的事
- 注意:它不保证所有依赖已完全加载(某些插件可能还没初始化),别在里面调用尚未 autoload 的类
- 脚本中若需使用项目类,必须显式
require __DIR__ . '/../vendor/autoload.php',因为 Composer 默认不加载 autoload - 错误写法:
"post-autoload-dump": "php artisan config:clear"→artisan类未加载,报Class 'App\Console\Kernel' not found
@php 是安全调用 PHP 的唯一方式
直接写 php script.php 极易出错:CI 环境中 Composer 可能用 php8.2 运行,但系统 php 命令指向 php7.4,导致语法错误或扩展缺失:
- 必须用
@php—— 它是 Composer 内置快捷方式,自动复用当前运行 Composer 的 PHP 可执行文件 - 数组格式更可靠:
"post-update-cmd": ["@php", "artisan", "migrate", "--force"],避免 shell 解析歧义 - PHP 回调写法必须是
public static方法:"MyClass::runMigrations",非静态方法会报Call to undefined method - Windows 用户慎用
rm -rf或cp,应统一封装进 PHP 脚本,用glob()+unlink()或Filesystem::cleanDirectory()
scripts 不该承担部署逻辑
把数据库迁移、前端构建、镜像上传塞进 scripts,等于把部署责任甩给依赖管理器——这会导致本地能跑、CI 失败、线上报错三连击:
-
post-update-cmd在composer install --no-dev时不触发,线上部署直接跳过关键步骤 - 钩子运行环境不可控:PHP 版本、扩展、PATH、用户权限可能和正式部署脚本不一致
- 错误默认被吞:某条命令失败(如
cp .env.example .env因目录不存在),composer install仍返回成功,线上启动崩在 dotenv 加载 - 真正稳的做法:把部署逻辑抽成独立脚本(如
bin/deploy),由 CI/CD 工具(GitHub Actions、GitLab CI)或运维工具(Deployer)调用;composer.json只负责装包
复杂点在于:钩子本身没有状态记忆,也不提供流程编排能力;它只是事件通知器。容易被忽略的是——你写的每一条命令,都得自己处理跨平台兼容、autoload 加载时机、退出码校验,而不是指望 Composer 替你兜底。











