404 Not Found

404 Not Found


nginx

Ciclo de Vida de Requisições do Laravel e o Kernel HTTP

O ciclo de vida da requisição é a "planta do motor" do Laravel—entendê-o, você passará de "saber usar o framework" para "compreender o framework".

1. O Que Você Vai Aprender


2. Uma História Real de um Desenvolvedor Sênior

(1) Problema: Depuração em caixa preta desperdiça horas

Alice encontrou um bug estranho no ShopMetrics: tudo funcionava bem localmente, mas após o deploy, um certo Facade retornava null. Ela não sabia qual classe o Facade estava chamando internamente, nem tinha certeza de onde o container de serviço o havia vinculado. Levou quatro horas vasculhando o código para descobrir que o método register() de um ServiceProvider continha uma verificação condicional, e a vinculação não havia sido registrada no branch de produção. Bob também aprendeu da forma difícil—ele não entendia a ordem de execução do middleware, o que fez com que o middleware de autenticação rodasse após o middleware CORS, resultando em um erro 401 durante a pré-validação de requisições.

(2) Solução Compreendendo o Ciclo de Vida

Uma vez que você compreende o ciclo de vida da requisição, pode identificar exatamente em qual estágio qualquer problema ocorre—seja uma incompatibilidade de rota, uma verificação de middleware falha, uma vinculação de container ausente ou um Provider que falhou ao carregar.

PHP
// Conhecer o ciclo de vida ajuda a depurar assim:
// 1. Verificar se a vinculação existe
app()->bound('payment.gateway');
// 2. Verificar qual provider a registrou
app()->getBindings()['payment.gateway']['concrete'];
// 3. Rastrear a ordem de execução do middleware
app()->make(\Illuminate\Foundation\Http\Kernel::class)->getMiddlewarePriority();

(3) Resultado

Usando técnicas de depuração do container, Alice identificou a causa do Facade retornar null em apenas 5 minutos, e Bob resolveu o problema de CORS imediatamente após ajustar a prioridade do middleware. Desenvolvedores que compreendem o ciclo de vida podem aumentar sua eficiência de depuração dez vezes.


3. Ciclo de Vida da Requisição

(1) Processo Completo

100%
flowchart TD
    A["public/index.php<br/>(Ponto de Entrada)"] --> B["Kernel HTTP<br/>(bootstrap/app.php)"]
    B --> C["Service Providers<br/>(Register & Boot)"]
    C --> D["Pipeline de Middleware<br/>(Global + Rota)"]
    D --> E{"Rota Correspondente?"}
    E -->|Sim| F["Controlador/Ação<br/>(Lógica de Negócio)"]
    E -->|Não| G["Fallback/404"]
    F --> H["Objeto Response"]
    G --> H
    H --> I["Enviar ao Cliente"]
    I --> J["Terminate<br/>(Hooks pós-resposta)"]

(2) Explicação Detalhada de Cada Estágio

Fase Arquivo/Classe Responsabilidades
Ponto de Entrada public/index.php Carregar autoload do Composer, criar instância da aplicação
Kernel bootstrap/app.php Configurar middleware, tratamento de exceções e roteamento
Registro de Provider config/app.providers Registrar Vinculação no Container
Inicialização de Provider boot() do Provider Executar lógica de inicialização
Middleware Global → Rota Filtrar/Modificar Requisições e Respostas
Distribuição de Rota Router Corresponder URL → Executar Controlador
Encerramento Middleware Terminable Realizar operações de limpeza após a resposta

(1) ▶ Exemplo: Visualizando os Estágios do Ciclo de Vida da Requisição

BASH
# Verificar provedores de serviço registrados
php artisan about --only=providers
# Listados: AppServiceProvider, AuthServiceProvider, etc.

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

# Verificar serviços vinculados no container
php artisan tinker
# app()->getBindings()
# Lista todas as vinculações de container registradas

Saída:

TEXT
# Comando executado com sucesso

4. Kernel HTTP e Kernel Console

O Laravel possui dois kernels: o kernel HTTP trata requisições web, e o kernel Console trata comandos Artisan.

(1) Configuração do Kernel no Laravel 11

PHP
// bootstrap/app.php — Configuração em arquivo único do Laravel 11
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();
Dimensão Kernel HTTP Kernel Console
Ponto de Entrada public/index.php Arquivo artisan
Objeto Processado Requisição HTTP Input do Console
Middleware Global + Rota Nenhum
Saída Resposta HTTP Saída do Console
Ambiente Requisições Web Comandos CLI

(1) ▶ Exemplo: Middleware Global Personalizado

PHP
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // Adicionar middleware global (executa em toda requisição)
    $middleware->append([
        \App\Http\Middleware\SetLocale::class,
    ]);

    // Remover um middleware global padrão
    $middleware->remove([
        \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
    ]);

    // Registrar alias para middleware de rota
    $middleware->alias([
        'tenant' => \App\Http\Middleware\TenantResolve::class,
        'role' => \App\Http\Middleware\CheckRole::class,
    ]);
})

Saída:

TEXT
// Execução bem-sucedida

5. Container de Serviço

O container de serviço é o coração do Laravel—ele gerencia a injeção de dependência e o ciclo de vida das classes.

(1) Vinculação

PHP
// app/Providers/AppServiceProvider.php
public function register(): void
{
    // Vincular interface à implementação
    $this->app->bind(
        PaymentGatewayInterface::class,
        StripeGateway::class,
    );

    // Vincular com closure (controle total)
    $this->app->bind('analytics.service', function ($app) {
        return new AnalyticsService(
            $app->make(CacheManager::class),
            $app['config']->get('analytics.ttl'),
        );
    });

    // Singleton — mesma instância toda vez
    $this->app->singleton(ShopMetricsConfig::class, function ($app) {
        return new ShopMetricsConfig(
            $app['config']->get('shopmetrics'),
        );
    });
}
Método de Vinculação Por Chamada Finalidade
bind() Criar uma Nova Instância Serviço Sem Estado
singleton() Reutilizar Instância Objetos Com Estado/Custosos
scoped() Criar nova instância para cada requisição Singleton por requisição
instance() Usar uma instância existente Objetos já criados

(2) Resolução

PHP
// Resolução automática via dica de tipo
class OrderController extends Controller
{
    public function __construct(
        private PaymentGatewayInterface $gateway, // resolvido automaticamente
    ) {}
}

// Resolução manual
$gateway = app(PaymentGatewayInterface::class);
$gateway = app()->make(PaymentGatewayInterface::class);
$analytics = resolve('analytics.service');

(1) ▶ Exemplo: Vinculação do Container de Serviço do ShopMetrics

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);
}

Saída:

TEXT
// Execução bem-sucedida

6. O Princípio dos Facades

Facades são os "proxies estáticos" do Laravel—eles usam sintaxe de chamada estática concisa e dependem do container de serviço para resolver os objetos reais nos bastidores.

(1) Como o Facade Funciona

100%
flowchart LR
    A["Cache::get('key')"] --> B["Cache Facade<br/>(chamada estática)"]
    B --> C["Facade::__callStatic()"]
    C --> D["Resolver do Container<br/>(cache manager)"]
    D --> E["CacheManager->get('key')"]

(2) Tabela de Padrões Comuns de Facade

Facade Classe Real Chave de Vinculação no Container
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. Injeção de Dependência

Dimensão Facade Injeção de Dependência
Sintaxe Chamada Estática Injeção no Construtor/Método
Testabilidade Simulável (Cache::fake()) Simulável (vinculação manual)
Suporte IDE Plug-ins/Arquivos de Suporte Necessários Dicas de Tipo Nativas
Simplicidade ✅ Chamada de uma linha ❌ Exige declaração de construtor
Cenários Recomendados Operações Simples/Controladores Classes de Service/Construtores

(1) ▶ Exemplo: Facade vs. Injeção de Dependência

PHP
// Usando Facade — conciso
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();
    });
}

// Usando DI — explícito, mais fácil de testar
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();
    });
}

Saída:

TEXT
// Execução bem-sucedida

7. Mecanismo de Inicialização do Service Provider

(1) Ciclo de Vida do Provider

TEXT
Requisição chega
  → Fase Register: register() de todos os providers chamado (sem booting ainda)
  → Fase Boot: boot() de todos os providers chamado (todas as vinculações disponíveis)
  → Aplicação pronta

(2) Provider Adiado

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];
    }
}
Tipo de Provider Quando Carregar Casos de Uso
Provider Padrão Carregado em toda requisição Funcionalidades Centrais/Comuns
Provider Adiado Carregar no primeiro uso Funcionalidades custosas/pouco frequentes

(1) ▶ Exemplo: ServiceProvider Personalizado do ShopMetrics

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
    {
        // Registrar alias de middleware
        $this->app->make(\Illuminate\Routing\Router::class)
            ->aliasMiddleware('tenant', TenantResolve::class);

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

        // Registrar listeners de eventos
        Event::listen(OrderPlaced::class, SendOrderNotification::class);
    }
}

Saída:

TEXT
// Execução bem-sucedida

8. Exemplo Completo: Rastreamento de Requisição do ShopMetrics

PHP
// ============================================
// Completo: Rastrear uma requisição do ShopMetrics
// Abrange: ciclo de vida, container, facade, provider
// ============================================

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

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

// 3. AppServiceProvider — Registrar vinculações
// public function register(): void
// {
//     $this->app->singleton(TenantManager::class);
//     $this->app->bind(PaymentGatewayInterface::class, StripeGateway::class);
// }

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

// 5. Controlador — Usar DI e Facades
class DashboardController extends Controller
{
    public function __construct(
        private TenantManager $tenantManager, // Resolvido via DI
    ) {}

    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. Resposta enviada → Middleware Terminable executa → Requisição concluída

❓ Perguntas Frequentes

P Qual é melhor, um Facade ou uma função auxiliar?
R Ambos chamam o mesmo serviço por baixo. Um Facade pode ser simulado para testes (Cache::fake()), enquanto uma função auxiliar é mais concisa (cache()). Recomendação: Use funções auxiliares para cenários simples, e use Facade quando simulação for necessária.
P Qual é a diferença entre register e boot?
R register apenas realiza vinculação no container e não pode depender de outros serviços; boot executa após todas as operações register serem concluídas e pode usar qualquer vinculação com segurança. Siga o princípio: "register apenas vincula; boot inicializa o container."
P Quando usar singleton, e quando usar bind?
R Use bind para serviços sem estado (onde uma nova instância é criada a cada vez, como um gerador de PDF); use singleton para serviços com estado ou com inicialização custosa (como conexões de banco de dados e gerenciadores de cache).
P Usar um Provider Adiado atrasa a primeira requisição?
R Há uma leve sobrecarga durante o carregamento inicial, mas isso reduz o tempo de inicialização de cada requisição subsequente. Se 90% das requisições para uma dada funcionalidade não a utilizam, adiar é a escolha certa.
P Como encontro a classe real associada a um dado Facade?
R Verifique a string retornada pelo método getFacadeAccessor() da classe Facade, depois procure a vinculação correspondente no container. Alternativamente, use app('cache') para recuperar a instância diretamente.
P O Laravel 11 removeu o Kernel.php?
R Sim, o Laravel 11 mescla o Kernel HTTP e o Kernel Console em bootstrap/app.php, usando uma API encadeada para configurar middleware, exceções e rotas. A funcionalidade permanece a mesma; apenas a configuração é mais centralizada.

📖 Resumo


📝 Exercícios

  1. Questão Básica (⭐): Use php artisan about para visualizar a lista de Service Providers do ShopMetrics, identifique quais são padrões do framework e quais são personalizados, e desenhe um fluxograma simplificado do ciclo de vida da requisição.

  2. Exercício Avançado (⭐⭐): Crie um ShopMetricsServiceProvider, use bind() para vincular ReportGeneratorInterface a PdfReportGenerator, e então use-o no controlador via injeção de dependência.

  3. Desafio (⭐⭐⭐): Implemente um Provider Adiado para carregar preguiçosamente o gateway de pagamento Stripe. Use a vinculação declarada em provides() e verifique via app()->resolved() que ela é realmente carregada apenas no primeiro uso.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%