post-root-package-install 仅在 composer create-project 初始化空项目时触发,用于执行不依赖 autoload 的纯文件操作;它在 vendor 生成前运行,不可调用第三方类或 require vendor/autoload.php。

post-root-package-install 脚本只在 composer create-project 时触发
这个脚本不是每次 composer install 都运行,它专为「从零生成新项目」设计。只有当 Composer 检测到当前目录是空的、且正在执行 create-project(比如 composer create-project laravel/laravel myapp)时,才会调用它。
常见误解是把它当成通用安装钩子——实际上你在已有项目里执行 composer install 或 composer update,它完全不会执行。
- 触发条件严格:必须是 root package(即项目本身)首次被安装,且无
vendor/目录 - 不适用于 CI/CD 中的常规依赖安装流程
- 无法用于初始化 Git 仓库、写入 .env 文件等「项目启动后」动作(那些该用
post-create-project-cmd)
它和 post-create-project-cmd 的关键区别在哪?
post-root-package-install 在依赖解包完成但尚未执行任何用户脚本前运行;而 post-create-project-cmd 是整个 create-project 流程的最后一步,此时 vendor/ 已就位、autoload 已生成、所有包都已安装完毕。
这意味着:
-
post-root-package-install里不能安全调用require_once 'vendor/autoload.php'—— autoload 文件可能还没生成 - 你无法在这个阶段使用其他包提供的类或函数(例如
symfony/console的Command类) - 适合做的操作仅限于:检查 PHP 版本、创建空目录(如
storage/)、复制骨架文件(cp .env.example .env)等纯文件系统操作
如何在 composer.json 中正确定义它?
它必须声明在根项目的 composer.json 中,且只能是字符串命令或可调用数组(不能是闭包)。注意:它不接收参数,Composer 不会传入 $event 对象。
{
"scripts": {
"post-root-package-install": [
"php -r \"copy('.env.example', '.env');\"",
"mkdir -p storage/logs storage/framework/{cache,sessions,views}"
]
}
}
如果你写成 "post-root-package-install": "MyScript::init",而 MyScript::init() 依赖 vendor/autoload.php,就会报 Class not found —— 因为此时 autoloader 还没生成。
- 推荐只用 shell 命令或内联 PHP(
php -r)做轻量初始化 - 避免 require / include 任何 vendor 下的代码
- 不要试图读取
composer.lock或解析已安装包信息 —— 它们可能尚未写入磁盘
为什么你大概率不该用它?
绝大多数所谓“项目初始化”需求其实属于 post-create-project-cmd 的职责范围。比如生成密钥(php artisan key:generate)、执行迁移(php artisan migrate:fresh)、初始化 Git 仓库 —— 这些都需要完整的依赖环境和 autoloader 支持。
post-root-package-install 的真实适用场景非常窄:仅限于「在 vendor 尚未准备好时,必须立刻干预文件系统」的边缘情况。例如某些模板项目需要在 vendor/ 创建前就准备好特定目录结构,或防止后续脚本因缺失目录而失败。
如果不确定,先试试 post-create-project-cmd;只有当你明确看到「vendor/autoload.php does not exist」错误,且必须在那之前操作文件,才考虑它。










