symfony/http-kernel
Symfony HttpKernel provides a structured request-to-response workflow built on EventDispatcher. It powers full-stack frameworks, micro-frameworks, and advanced CMSs by handling kernel events, controller resolution, and response generation in a flexible pipeline.
Installation:
composer require symfony/http-kernel
Laravel already includes this component under the hood, so no explicit installation is needed unless extending functionality.
Core Concepts:
HttpKernel converts a Request into a Response via a structured pipeline.HttpKernelInterface, Kernel, Request, Response, EventDispatcher.First Use Case:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
$request = Request::createFromGlobals();
$kernel = new \App\Http\Kernel(); // Laravel's Kernel extends Symfony's Kernel
$response = $kernel->handle($request);
$response->send();
Where to Look First:
app/Http/Kernel.php (extends Symfony’s Kernel).vendor/symfony/http-kernel/ for core classes.Request Handling Pipeline:
// Laravel's Kernel extends Symfony's Kernel and implements HttpKernelInterface
$response = $kernel->handle(
$request,
HttpKernelInterface::MAIN_REQUEST, // or SUB_REQUEST
$catch = true // whether to catch exceptions
);
@include in Blade).Middleware Integration:
Laravel’s middleware leverages Symfony’s EventDispatcher:
// In Kernel.php
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
// ...
];
TerminableMiddlewareInterface or MiddlewareInterface.Event-Driven Extensions:
// Listen to kernel events (e.g., request/response lifecycle)
$dispatcher->addListener(KernelEvents::REQUEST, function (KernelEvent $event) {
$request = $event->getRequest();
// Modify request or add data
});
Sub-Requests for Fragments:
// Example: Rendering a partial via a sub-request
$subRequest = $request->duplicate(
null,
null,
['_route' => 'partial.route']
);
$fragment = $kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
Custom Kernel for CLI/Non-HTTP:
// For non-HTTP contexts (e.g., CLI commands)
$kernel = new class extends Kernel {
public function boot() { /* ... */ }
public function handle($request, $type = self::MAIN_REQUEST, $catch = true) { /* ... */ }
};
App\Http\Kernel instead of reinventing the wheel. Override methods like:
public function handle($request, $type = self::MAIN_REQUEST, $catch = true)
HttpCache for Performance:
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
$cache = new HttpCache($kernel, $cacheDir);
$response = $cache->handle($request);
HttpKernelBrowser:
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\HttpKernel\HttpKernelBrowser;
$client = new HttpKernelBrowser($kernel);
$client->request('GET', '/');
Locale Handling:
HttpKernel resets the router locale to the default after handling a request. If you need to preserve it (e.g., for multi-language APIs), manually reset it:
$router->setDefaultLocale($originalLocale);
HEAD Requests and Security:
#[IsGranted]). Ensure your security logic accounts for this:
// In a controller/middleware
if ($request->isMethod('HEAD')) {
// Handle HEAD-specific logic
}
Variadic Arguments:
# references in controller arguments (e.g., #invalid) can cause errors. Validate early:
if (str_contains($argument, '#') && !preg_match('/#\w+$/', $argument)) {
throw new \InvalidArgumentException('Invalid argument reference');
}
Enum Handling:
RequestPayloadValueResolver may fail silently. Explicitly handle invalid values:
try {
$enumValue = MyEnum::from($request->request->get('field'));
} catch (\ValueError $e) {
$enumValue = MyEnum::DEFAULT;
}
HttpCache in Worker Mode:
HttpCache with workers (e.g., Symfony Cloud), ensure the cache directory is shared:
# config/packages/http_cache.yaml
framework:
http_cache:
cache_dir: '%kernel.project_dir%/var/cache/http_cache'
Enable Verbose Logging:
$dispatcher->addListener(KernelEvents::EXCEPTION, function (GetResponseForExceptionEvent $event) {
\Log::error('Kernel Exception', [
'exception' => $event->getThrowable(),
'request' => $event->getRequest()->query->all(),
]);
});
Inspect Request/Response:
// Dump request attributes
\Symfony\Component\VarDumper\Caster\Caster::setCasters([
new \Symfony\Component\HttpFoundation\RequestCaster(),
]);
dump($request);
// Dump response
dump($response->getContent());
Check for Deprecated Methods:
Kernel::VERSION. Use KernelInterface::VERSION instead.Custom Event Listeners:
// Listen to kernel.finish_request
$dispatcher->addListener(KernelEvents::FINISH_REQUEST, function (FinishRequestEvent $event) {
$event->getResponse()->headers->set('X-Custom-Header', 'value');
});
Override Kernel Bootstrapping:
// In a custom Kernel class
public function boot()
{
parent::boot();
// Add custom boot logic (e.g., register services)
}
Modify Request/Response Globally:
// Add a global middleware to modify requests
$dispatcher->addListener(KernelEvents::REQUEST, function (KernelEvent $event) {
$event->setRequest($event->getRequest()->withHeader('X-Processed', 'true'));
});
Handle Exceptions:
$dispatcher->addListener(KernelEvents::EXCEPTION, function (GetResponseForExceptionEvent $event) {
if ($event->getThrowable() instanceof \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface) {
return;
}
$event->setResponse(new Response('Custom error', 500));
});
Sub-Request Caching:
HttpCache:
$cache = new HttpCache($kernel, $cacheDir);
$fragment = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
How can I help you explore Laravel packages today?