在 composer.json 的 scripts 中需用正确事件名(如 post-update-cmd)和可执行格式(如 ["php", "scripts/fix-perms.php"]),确保路径正确、权限合法、事件名全小写中划线分隔,并通过 autoload-dev 加载类方法,避免阻塞操作。

composer.json 里怎么写 scripts 才能自动运行 PHP?
Composer 的 scripts 不是“安装后立刻执行任意代码”的开关,而是按明确生命周期触发的钩子。想在 composer install 或 composer update 结束后跑一段 PHP,得选对事件名,且脚本必须可被 Composer 正确调用。
常见错误是直接写 php my-script.php 却忘了路径问题,或误以为 post-install-cmd 会在所有场景下触发(其实它不触发于 composer require 的首次安装)。
-
post-install-cmd:只在composer install时触发,且仅当vendor/autoload.php已存在(即不是首次安装) -
post-update-cmd:每次composer update后都触发,更稳定,适合大多数“安装后动作” - 脚本值可以是字符串命令,也可以是数组:
["php", "scripts/fix-perms.php"],推荐后者——避免 shell 解析歧义 - 确保脚本文件有执行权限(Linux/macOS),且第一行没加
#!/usr/bin/env php(Composer 不走 shebang,会报错)
为什么写了 scripts 却完全没执行?
最常踩的坑是事件名拼错或没声明为“可执行”。Composer 不报错、不提示,静默跳过无效 script 条目。
检查点:
立即学习“PHP免费学习笔记(深入)”;
- 确认
composer.json根级有"scripts"字段,不是嵌套在"extra"或其他地方 - 事件名必须全小写、中划线分隔,比如
post-autoload-dump不能写成PostAutoloadDump - 如果脚本是 PHP 类方法,格式必须是
"MyClass::myMethod",且类已通过 autoload 加载(推荐用autoload-dev注册) - 运行时加
-v参数:composer install -v,能看到 “Executing script …” 日志,没这行就说明根本没注册上
用 PHP 类方法当钩子,要注意什么?
比起写独立脚本文件,用类方法更易测试、可复用,但依赖加载时机很关键——post-install-cmd 触发时,vendor/autoload.php 可能还没生成,导致类找不到。
稳妥做法:
- 把钩子逻辑放进
src/或scripts/下,并在composer.json的"autoload-dev"中声明 PSR-4 映射 - 钩子方法必须是
public static,参数可选,Composer 会传入$event对象(类型ComposerScriptEvent) - 别在方法里直接
require 'vendor/autoload.php'——Composer 已处理好 autoloader,重复 require 可能破坏命名空间 - 示例:
"post-update-cmd": ["MyBuild\Scripts::clearCache"],对应MyBuildScripts::clearCache()
性能和兼容性:这些钩子真适合干重活吗?
不适合。Composer 的 scripts 是同步阻塞执行的,卡在某个钩子上,整个 install 或 update 就卡住。CI 环境尤其敏感。
- 避免在钩子里做网络请求、文件扫描、数据库迁移——这些该交给部署脚本或 CI 流程单独跑
- Windows 用户注意:用
php script.php比用./script.php更可靠,后者在 Git Bash 下常因路径解析失败 - PHP 版本兼容性:钩子脚本运行在当前 CLI PHP 环境下,和项目
require的 PHP 版本无关。若脚本用了match表达式,而系统 PHP 是 8.0 以下,直接 fatal error - 如果只是生成配置或清理缓存,优先用
post-autoload-dump——它比post-update-cmd更轻量,且每次 autoloader 更新都触发,覆盖更多场景
真正难搞的是跨平台路径拼接和钩子执行顺序——post-install-cmd 和 post-autoload-dump 谁先谁后?文档没明说,实测取决于是否首次安装,得自己加日志验证。











