404 Not Found

404 Not Found


nginx

Laravel Request Lifecycle and the HTTP Kernel

The request lifecycle is the "engine blueprint" of Laravel—understand it, and you'll go from "knowing how to use the framework" to "understanding the framework."

1. What You'll Learn


2. A True Story of a Senior Developer

(1) Pain Point: Black-box debugging wastes hours

Alice encountered a strange bug in ShopMetrics: everything worked fine locally, but after deployment, a certain Facade returned null. She didn't know which class the Facade was calling internally, nor was she sure where the service container had bound it. It took her four hours of digging through the code to discover that the register() method of a ServiceProvider contained a conditional check, and the binding hadn't been registered in the production branch. Bob had also learned the hard way—he didn't understand the execution order of middleware, which caused the authentication middleware to run after the CORS middleware, resulting in a 401 error during the pre-validation of requests.

(2) Understanding the Life Cycle Solution

Once you understand the request lifecycle, you can pinpoint exactly at which stage any issue occurs—whether it's a routing mismatch, a failed middleware check, a missing container binding, or a Provider that failed to load.

PHP
// Knowing the lifecycle helps you debug like this:
// 1. Check if the binding exists
app()->bound('payment.gateway');
// 2. Check which provider registered it
app()->getBindings()['payment.gateway']['concrete'];
// 3. Trace middleware execution order
app()->make(\Illuminate\Foundation\Http\Kernel::class)->getMiddlewarePriority();

(3) Revenue

Using container debugging techniques, Alice pinpointed the cause of the Facade returning null in just 5 minutes, and Bob resolved the CORS issue immediately after adjusting the middleware priority. Developers who understand the lifecycle can boost their debugging efficiency tenfold.


3. Request Lifecycle

(1) Complete Process

100%
flowchart TD
    A["public/index.php<br/>(Entry Point)"] --> B["HTTP Kernel<br/>(bootstrap/app.php)"]
    B --> C["Service Providers<br/>(Register & Boot)"]
    C --> D["Middleware Pipeline<br/>(Global + Route)"]
    D --> E{"Route Matched?"}
    E -->|Yes| F["Controller/Action<br/>(Business Logic)"]
    E -->|No| G["Fallback/404"]
    F --> H["Response Object"]
    G --> H
    H --> I["Send to Client"]
    I --> J["Terminate<br/>(Post-response hooks)"]

(2) Detailed Explanation of Each Stage

Phase File/Class Responsibilities
Entry Point public/index.php Load Composer autoload, create application instance
Kernel bootstrap/app.php Configure middleware, exception handling, and routing
Provider Registration config/app.providers Register Container Binding
Provider Startup Provider boot() Execute startup logic
Middleware Global → Route Filter/Modify Requests and Responses
Route Distribution Router Match URL → Execute Controller
Termination Terminable Middleware Perform cleanup operations after a response

(1) ▶ Example: Viewing the Stages of the Request Lifecycle

BASH
# Check registered service providers
php artisan about --only=providers
# Listed: AppServiceProvider, AuthServiceProvider, etc.

# Check middleware pipeline
php artisan route:list --columns=method,uri,middleware
# GET /dashboard → auth, tenant.resolve, verified

# Check bound services in container
php artisan tinker
# app()->getBindings()
# Lists all registered container bindings

Output:

TEXT
# Command executed successfully

4. HTTP Kernel and Console Kernel

Laravel has two kernels: the HTTP kernel handles web requests, and the Console kernel handles Artisan commands.

(1) Laravel 11 Kernel Configuration

PHP
// bootstrap/app.php — Laravel 11 single-file configuration
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->appendToGuestList([
            '/api/*',
        ]);
        $middleware->alias([
            'tenant.resolve' => \App\Http\Middleware\TenantResolve::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();
Dimension HTTP Kernel Console Kernel
Entry public/index.php artisan File
Object Being Processed HTTP Request Console Input
Middleware Global + Route None
Output HTTP Response Console Output
Environment Web Requests CLI Commands

(1) ▶ Example: Custom Global Middleware

PHP
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // Add global middleware (runs on every request)
    $middleware->append([
        \App\Http\Middleware\SetLocale::class,
    ]);

    // Remove a default global middleware
    $middleware->remove([
        \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
    ]);

    // Register alias for route middleware
    $middleware->alias([
        'tenant' => \App\Http\Middleware\TenantResolve::class,
        'role' => \App\Http\Middleware\CheckRole::class,
    ]);
})

Output:

TEXT
// Execution Successful

5. Service Containers

The service container is at the heart of Laravel—it manages dependency injection and the lifecycle of classes.

(1) Binding

PHP
// app/Providers/AppServiceProvider.php
public function register(): void
{
    // Bind interface to implementation
    $this->app->bind(
        PaymentGatewayInterface::class,
        StripeGateway::class,
    );

    // Bind with closure (full control)
    $this->app->bind('analytics.service', function ($app) {
        return new AnalyticsService(
            $app->make(CacheManager::class),
            $app['config']->get('analytics.ttl'),
        );
    });

    // Singleton — same instance every time
    $this->app->singleton(ShopMetricsConfig::class, function ($app) {
        return new ShopMetricsConfig(
            $app['config']->get('shopmetrics'),
        );
    });
}
Binding Method Per Call Purpose
bind() Create a New Instance Stateless Service
singleton() Reuse Examples Stateful/Costly Objects
scoped() Create a new instance for each request Request-level singleton
instance() Use an existing instance Created objects

(2) Analysis

PHP
// Automatic resolution via type-hint
class OrderController extends Controller
{
    public function __construct(
        private PaymentGatewayInterface $gateway, // auto-resolved
    ) {}
}

// Manual resolution
$gateway = app(PaymentGatewayInterface::class);
$gateway = app()->make(PaymentGatewayInterface::class);
$analytics = resolve('analytics.service');

(1) ▶ Example: ShopMetrics Service Container Binding

PHP
// app/Providers/AppServiceProvider.php
public function register(): void
{
    $this->app->bind(
        \App\Contracts\ReportGeneratorInterface::class,
        \App\Services\PdfReportGenerator::class,
    );

    $this->app->singleton(
        \App\Services\TenantManager::class,
        fn ($app) => new TenantManager(
            $app->make(\App\Models\Tenant::class),
        ),
    );

    $this->app->when(ShopController::class)
        ->needs(\App\Contracts\FileStorageInterface::class)
        ->give(\App\Services\S3StorageService::class);
}

Output:

TEXT
// Execution Successful

6. The Facades Principle

Facades are Laravel's "static proxies"—they use concise static call syntax and rely on the service container to resolve the actual objects behind the scenes.

(1) How the Facade Works

100%
flowchart LR
    A["Cache::get('key')"] --> B["Cache Facade<br/>(static call)"]
    B --> C["Facade::__callStatic()"]
    C --> D["Resolve from Container<br/>(cache manager)"]
    D --> E["CacheManager->get('key')"]

(2) Table of Common Facade Patterns

Facade Actual Class Container Binding Key
Cache CacheManager cache
DB DatabaseManager db
Event Dispatcher events
Log LogManager log
Mail MailManager mail
Queue QueueManager queue
Route Router router
Storage FileManager filesystem

(3) Facade vs. Dependency Injection

Dimension Facade Dependency Injection
Syntax Static Call Constructor/Method Injection
Testability Mockable (Cache::fake()) Mockable (manual binding)
IDE Support Plug-ins/Support Files Required Native Type Hints
Simplicity ✅ One-line call ❌ Requires a constructor declaration
Recommended Scenarios Simple Operations/Controllers Service Classes/Constructors

(1) ▶ Example: Facade vs. Dependency Injection

PHP
// Using Facade — concise
use Illuminate\Support\Facades\Cache;

public function getShopStats(int $shopId): array
{
    return Cache::remember("shop.stats.{$shopId}", 3600, function () use ($shopId) {
        return Shop::findOrFail($shopId)->getStats();
    });
}

// Using DI — explicit, easier to test
public function __construct(
    private CacheManager $cache,
) {}

public function getShopStats(int $shopId): array
{
    return $this->cache->remember("shop.stats.{$shopId}", 3600, function () use ($shopId) {
        return Shop::findOrFail($shopId)->getStats();
    });
}

Output:

TEXT
// Execution Successful

7. Service Provider Startup Mechanism

(1) Provider Lifecycle

TEXT
Request arrives
  → Register Phase: all providers' register() called (no booting yet)
  → Boot Phase: all providers' boot() called (all bindings available)
  → Application ready

(2) Deferred Provider

PHP
// app/Providers/PaymentServiceProvider.php
class PaymentServiceProvider extends ServiceProvider
{
    protected bool $defer = true;

    public function register(): void
    {
        $this->app->singleton(StripeGateway::class, function ($app) {
            return new StripeGateway(config('services.stripe'));
        });
    }

    public function provides(): array
    {
        return [StripeGateway::class];
    }
}
Provider Type When to Load Use Cases
Standard Provider Loaded on every request Core/Common Features
Deferred Provider Load on first use Expensive/low-frequency features

(1) ▶ Example: ShopMetrics Custom ServiceProvider

PHP
// app/Providers/ShopMetricsServiceProvider.php
class ShopMetricsServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            ReportGeneratorInterface::class,
            PdfReportGenerator::class,
        );

        $this->app->singleton(TenantManager::class);
    }

    public function boot(): void
    {
        // Register middleware alias
        $this->app->make(\Illuminate\Routing\Router::class)
            ->aliasMiddleware('tenant', TenantResolve::class);

        // Register view composer
        View::composer('dashboard.*', NavigationComposer::class);

        // Register event listeners
        Event::listen(OrderPlaced::class, SendOrderNotification::class);
    }
}

Output:

TEXT
// Execution Successful

8. Comprehensive Example: ShopMetrics Request Tracing

PHP
// ============================================
// Comprehensive: Trace a ShopMetrics request
// Covers: lifecycle, container, facade, provider
// ============================================

// 1. public/index.php — Entry point
// $app = require_once __DIR__.'/../bootstrap/app.php';
// $app->handleRequest();

// 2. bootstrap/app.php — Kernel configuration
// return Application::configure(basePath: dirname(__DIR__))
//     ->withRouting(web: ..., api: ...)
//     ->withMiddleware(fn ($m) => $m->append([SetLocale::class]))
//     ->create();

// 3. AppServiceProvider — Register bindings
// public function register(): void
// {
//     $this->app->singleton(TenantManager::class);
//     $this->app->bind(PaymentGatewayInterface::class, StripeGateway::class);
// }

// 4. Route: GET /{tenant}/dashboard
// Route::middleware(['auth', 'tenant'])->get('/{tenant}/dashboard', [DashboardController::class, 'index']);

// 5. Controller — Use DI and Facades
class DashboardController extends Controller
{
    public function __construct(
        private TenantManager $tenantManager, // DI resolved
    ) {}

    public function index(Request $request): View
    {
        $tenant = $this->tenantManager->current();
        $stats = Cache::remember("dashboard.{$tenant->id}", 300, function () use ($tenant) {
            return [
                'revenue' => $tenant->shops()->sum('revenue'),
                'orders' => $tenant->orders()->count(),
                'shops' => $tenant->shops()->active()->count(),
            ];
        });

        return view('dashboard.index', compact('tenant', 'stats'));
    }
}

// 6. Response sent → Terminable middleware runs → Request complete

❓ FAQ

Q Which is better, a Facade or a helper function?
A Both call the same service under the hood. A Facade can be mocked for testing (Cache::fake()), while a helper is more concise (cache()). Recommendation: Use helper functions for simple scenarios, and use Facade when mocking is required.
Q What is the difference between register and boot?
A register only performs container binding and cannot depend on other services; boot runs after all register operations are complete and can safely use any bindings. Follow the principle: "register only binds; boot starts the container."
Q When should you use a singleton, and when should you use a bind?
A Use a bind for stateless services (where a new instance is created each time, such as a PDF generator); use a singleton for stateful services or those with expensive initialization (such as database connections and cache managers).
Q Does using a Deferred Provider slow down the first request?
A There is a slight overhead during the initial load, but it reduces the startup time for each subsequent request overall. If 90% of requests for a given feature do not use it, deferring is the right choice.
Q How do I find the actual class associated with a given Facade?
A Check the string returned by the getFacadeAccessor() method of the Facade class, then look up the corresponding binding in the container. Alternatively, use app('cache') to retrieve the instance directly.
Q Has Laravel 11 removed Kernel.php?
A Yes, Laravel 11 merges the HTTP Kernel and Console Kernel into bootstrap/app.php, using a chained API to configure middleware, exceptions, and routes. The functionality remains the same; it's just that the configuration is more centralized.

📖 Summary


📝 Exercises

  1. Basic Question (⭐): Use php artisan about to view the ShopMetrics Service Provider list, identify which ones are framework defaults and which are custom, and draw a simplified flowchart of the request lifecycle.

  2. Advanced Exercise (⭐⭐): Create a ShopMetricsServiceProvider, use bind() to bind ReportGeneratorInterface to PdfReportGenerator, and then use it in the controller via dependency injection.

  3. Challenge (⭐⭐⭐): Implement a Deferred Provider to lazy-load the Stripe payment gateway. Use the binding declared in provides() and verify via app()->resolved() that it is indeed loaded only upon first use.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏