public/index.php 仅加载自动加载器、应用实例和HTTP内核,真正的请求处理始于 $kernel->handle();其五阶段含 bootstrap、中间件管道、路由分发、控制器执行与响应封装;$response->send() 发送响应后,$kernel->terminate() 异步执行清理任务。

public/index.php 不是“开始处理请求”的地方,它只是加载器和启动器;真正的请求调度始于 $kernel->handle(),而响应发送早在 $kernel->terminate() 执行前就已完成。
入口文件 public/index.php 只做三件事
它不解析 URI、不读取 session、不匹配路由——这些全由后续组件完成。它的作用极其明确:
- 加载
vendor/autoload.php:让 PHP 能按命名空间自动找到类文件 - 执行
bootstrap/app.php:返回一个Illuminate\Foundation\Application实例(服务容器),不是 HTTP kernel - 调用
$app->make(Illuminate\Contracts\Http\Kernel::class)拿到App\Http\Kernel实例,然后立即传入请求
常见错误现象:Class 'App\Http\Kernel' not found 通常是因为 bootstrap/app.php 中未正确绑定该类,或 App\Http\Kernel 文件路径/命名空间写错。
Http\Kernel::handle() 的五阶段执行链
这个方法才是请求生命周期的主干道,内部按固定顺序执行,不可跳过或重排:
-
bootstrap():仅首次请求触发(FPM 模式下可能复用进程),加载配置、日志、异常处理器、环境变量(.env)、注册服务提供者(register()→boot()) -
sendRequestThroughRouter():核心管道,把请求塞进中间件洋葱栈 + 路由分发器 - 全局中间件执行(
$middleware):如StartSession、VerifyCsrfToken,注意它们会修改$request对象本身 - 路由匹配与分发:匹配成功后,
Router构建ControllerDispatcher,再把请求二次送入控制器级中间件(middleware()或构造函数注入) - 控制器方法执行:返回值(数组、视图、JSON、重定向等)被
Router自动封装为Response实例
关键细节:同一个中间件(比如 auth)若同时出现在全局栈和控制器上,会执行两次——第二次常因 session 已被读取导致 Auth::user() 返回 null 或旧缓存值。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
$response->send() 和 $kernel->terminate() 的分工误区
这两行代码在 index.php 末尾紧挨着,但语义完全隔离:
-
$response->send():直接向 SAPI(如 PHP-FPM 的 stdout)输出响应头+响应体,**此时浏览器已开始接收数据** -
$kernel->terminate():纯粹异步钩子,不参与响应生成或发送;常用于关闭数据库连接、记录慢查询、触发队列任务,但不能修改已发出的响应
性能影响:在 terminate() 中做耗时操作(如同步 HTTP 请求、大文件写入)不会阻塞用户响应,但会延长 PHP 进程存活时间,影响 FPM worker 复用率。
服务提供者注册时机与单例生命周期
所有 config/app.php 中的 providers 都在 bootstrap() 阶段完成 register() 和 boot(),但要注意:
-
register()阶段只能绑定容器实例($this->app->singleton()),不能依赖其他已注册服务(如 DB、Cache 尚未 ready) -
boot()阶段才可安全使用其他服务,也支持事件监听器注册(Event::listen()) -
Application是单例,但它的绑定对象(如Request、Session)是每次请求新建的——PHP 请求生命周期结束即销毁,不存在跨请求共享
容易被忽略的一点:你在 boot() 里用 $this->app->bind() 绑定的类,如果构造函数依赖尚未 boot() 完成的服务,就会报 “Target class does not exist” 或循环依赖错误。

















