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
- Ciclo de vida da requisição: public/index.php → Kernel → Pipeline → Response
- Arquitetura de kernel duplo com Kernel HTTP e Kernel Console
- Vinculação e Resolução do Container de Serviço: bind/singleton/make
- Facades: Princípios e Mecanismos de Proxy Estático
- Ordem de inicialização de Providers e Providers adiados
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.
// 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
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
# 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:
# 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
// 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
// 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:
// 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
// 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
// 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
// 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:
// 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
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
// 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:
// Execução bem-sucedida
7. Mecanismo de Inicialização do Service Provider
(1) Ciclo de Vida do Provider
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
// 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
// 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:
// Execução bem-sucedida
8. Exemplo Completo: Rastreamento de Requisição do ShopMetrics
// ============================================
// 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
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.register e boot?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."getFacadeAccessor() da classe Facade, depois procure a vinculação correspondente no container. Alternativamente, use app('cache') para recuperar a instância diretamente.Kernel.php?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
- Ciclo de vida da requisição: index.php → Kernel → Providers → Middleware → Rota → Controlador → Response
- O Kernel HTTP trata requisições web, e o Kernel Console trata comandos Artisan
- O container de serviço gerencia e injeta dependências:
bind()cria uma nova instância, enquantosingleton()reutiliza a instância - O Facade é um proxy estático; usa o container para resolver o objeto real por baixo e suporta testes com mock
- O processo do Provider consiste em duas fases: register (vinculação) e boot (inicialização)
- Provider Adiado: Carregamento adiado reduz sobrecarga desnecessária de inicialização de serviços
📝 Exercícios
-
Questão Básica (⭐): Use
php artisan aboutpara 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. -
Exercício Avançado (⭐⭐): Crie um
ShopMetricsServiceProvider, usebind()para vincularReportGeneratorInterfaceaPdfReportGenerator, e então use-o no controlador via injeção de dependência. -
Desafio (⭐⭐⭐): Implemente um Provider Adiado para carregar preguiçosamente o gateway de pagamento Stripe. Use a vinculação declarada em
provides()e verifique viaapp()->resolved()que ela é realmente carregada apenas no primeiro uso.



