服务提供者的 register 阶段仅允许绑定服务,boot 阶段才可安全使用已注册服务;register 在容器未就绪时执行,boot 在所有 register 完成后执行。

服务提供者是 Laravel 应用启动时管理依赖注册与初始化的统一入口,register 和 boot 是两个严格分离、不可互换的关键阶段。在 Laravel 6 中,这个机制已非常稳定,理解它们的核心差异,关键在于“容器是否就绪”。
register:只做绑定,不碰任何服务
这是最早执行的阶段,所有服务提供者的 register() 方法会在应用启动初期、按 config/app.php 中 providers 数组顺序依次调用——但此时服务容器还是“空架子”:核心服务(如 config、router、db、log)尚未注册,你无法安全使用它们。
- 只能调用
$this->app->bind()、singleton()、instance()等绑定方法 - 不能调用
$this->app->make('router')或config('app.debug'),大概率返回null或默认值 - 不能触发副作用:不读数据库、不发请求、不写日志、不注册路由或事件
- Artisan 命令必须在此注册:
$this->commands([MyCommand::class])
boot:等全部 register 完了,才开始干活
boot() 在所有服务提供者的 register() 全部执行完毕后,才统一调用。这时容器已基本构建完成,Laravel 的核心服务和你自己的已绑定服务都可安全访问。
- 可以放心使用
Route::get()、view()->composer()、Event::listen() - 能读取完整配置:
config('payment.driver') - 可依赖其他服务提供者注册的服务,只要它已在
providers数组中声明(顺序不影响可用性,因所有 register 已完成) - 适合发布视图、注册 Blade 组件、监听模型事件、设置全局中间件
常见错误与对应修正
很多运行时异常(比如 Call to a member function share() on null)都源于混淆这两个阶段:
- ❌ 在
register()里写view()->share('key', 'value')→ ✅ 搬到boot() - ❌
register()中尝试$this->app->make(MyService::class)并立刻调用方法 → ✅ 改为绑定,使用时再解析;或把调用逻辑移到boot() - ❌ 把路由定义放在
register()→ ✅ 路由必须在boot(),因为Route类依赖router服务,而它在register阶段不可用
加载顺序不是“一个 provider 的 register → boot”,而是两轮扫荡
Laravel 6 启动流程是严格的两阶段:
- 第一轮:逐个执行所有 provider 的
register()(顺序依config/app.php) - 第二轮:再逐个执行所有 provider 的
boot()(同样依数组顺序)
这意味着,即使 A 在数组里排在 B 后面,A 的 boot() 也能安全使用 B 在其 register() 中绑定的服务——因为所有 register 已结束。


















