乐于分享
好东西不私藏

Symfony HttpKernel 源码:框架的心脏

Symfony HttpKernel 源码:框架的心脏

HttpKernel 是 Symfony 的核心组件,Laravel 也基于它构建。

今天深入分析 HttpKernel 的实现原理。


HttpKernel 概述

HttpKernel 负责将 Request 转换为 Response。

interfaceHttpKernelInterface
{
publicfunctionhandle(
        Request $request, 
        int $type = self::MAIN_REQUEST, 
        bool $catch = true
    )
Response
;
}

核心流程

// Symfony\Component\HttpKernel\HttpKernel

publicfunctionhandle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true)Response
{
    $request->headers->set('X-Php-Ob-Level', (string) ob_get_level());

try {
return$this->handleRaw($request, $type);
    } catch (\Exception $e) {
if (!$catch) {
throw $e;
        }
return$this->handleThrowable($e, $request, $type);
    }
}

privatefunctionhandleRaw(Request $request, int $type = self::MAIN_REQUEST)Response
{
// 1. 触发 kernel.request 事件
    $event = new RequestEvent($this, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::REQUEST);

if ($event->hasResponse()) {
return$this->filterResponse($event->getResponse(), $request, $type);
    }

// 2. 解析控制器
if (false === $controller = $this->resolver->getController($request)) {
thrownew NotFoundHttpException();
    }

// 3. 触发 kernel.controller 事件
    $event = new ControllerEvent($this, $controller, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::CONTROLLER);
    $controller = $event->getController();

// 4. 解析控制器参数
    $arguments = $this->argumentResolver->getArguments($request, $controller);

// 5. 触发 kernel.controller_arguments 事件
    $event = new ControllerArgumentsEvent($this, $controller, $arguments, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS);
    $arguments = $event->getArguments();

// 6. 调用控制器
    $response = $controller(...$arguments);

// 7. 处理响应
if (!$response instanceof Response) {
        $event = new ViewEvent($this, $request, $type, $response);
$this->dispatcher->dispatch($event, KernelEvents::VIEW);

if ($event->hasResponse()) {
            $response = $event->getResponse();
        } else {
thrownew \LogicException('Controller must return a Response');
        }
    }

return$this->filterResponse($response, $request, $type);
}

事件系统

HttpKernel 通过事件实现扩展。

事件
触发时机
kernel.request
请求开始
kernel.controller
控制器解析后
kernel.controller_arguments
参数解析后
kernel.view
控制器返回非 Response
kernel.response
响应发送前
kernel.finish_request
请求处理完成
kernel.terminate
响应发送后
kernel.exception
发生异常

事件监听示例

useSymfony\Component\HttpKernel\Event\RequestEvent;
useSymfony\Component\HttpKernel\KernelEvents;

classRequestListener
{
publicfunctiononKernelRequest(RequestEvent $event)void
{
        $request = $event->getRequest();

// 检查 API Token
if (!$request->headers->has('X-API-Token')) {
            $event->setResponse(new JsonResponse([
'error' => 'Missing API token'
            ], 401));
        }
    }
}

// 注册监听器
$dispatcher->addListener(
    KernelEvents::REQUEST, 
    [new RequestListener(), 'onKernelRequest']
);

控制器解析器

// Symfony\Component\HttpKernel\Controller\ControllerResolver

publicfunctiongetController(Request $request)callable|false
{
// 从请求属性获取 _controller
if (!$controller = $request->attributes->get('_controller')) {
returnfalse;
    }

// 字符串格式:App\Controller\UserController::index
if (is_string($controller)) {
if (str_contains($controller, '::')) {
            $controller = explode('::', $controller, 2);
        } else {
// 可调用类
return$this->instantiateController($controller);
        }
    }

// 数组格式:[UserController::class, 'index']
if (is_array($controller)) {
if (is_string($controller[0])) {
            $controller[0] = $this->instantiateController($controller[0]);
        }
return $controller;
    }

return $controller;
}

参数解析器

// Symfony\Component\HttpKernel\Controller\ArgumentResolver

publicfunctiongetArguments(Request $request, callable $controller)array
{
    $arguments = [];

// 获取控制器方法的参数
    $reflection = new \ReflectionMethod($controller[0], $controller[1]);

foreach ($reflection->getParameters() as $param) {
// 遍历参数解析器
foreach ($this->argumentValueResolvers as $resolver) {
if ($resolver->supports($request, $param)) {
                $arguments[] = $resolver->resolve($request, $param);
continue2;
            }
        }

// 使用默认值
if ($param->isDefaultValueAvailable()) {
            $arguments[] = $param->getDefaultValue();
        } else {
thrownew \RuntimeException("Cannot resolve argument {$param->getName()}");
        }
    }

return $arguments;
}

内置参数解析器

// Request 参数
classRequestValueResolverimplementsArgumentValueResolverInterface
{
publicfunctionsupports(Request $request, ArgumentMetadata $argument)bool
{
return Request::class === $argument->getType();
    }

publicfunctionresolve(Request $request, ArgumentMetadata $argument)iterable
{
yield $request;
    }
}

// 路由参数
classRequestAttributeValueResolverimplementsArgumentValueResolverInterface
{
publicfunctionsupports(Request $request, ArgumentMetadata $argument)bool
{
return $request->attributes->has($argument->getName());
    }

publicfunctionresolve(Request $request, ArgumentMetadata $argument)iterable
{
yield $request->attributes->get($argument->getName());
    }
}

响应过滤

privatefunctionfilterResponse(Response $response, Request $request, int $type)Response
{
// 触发 kernel.response 事件
    $event = new ResponseEvent($this, $request, $type, $response);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);

// 触发 kernel.finish_request 事件
$this->finishRequest($request, $type);

return $event->getResponse();
}

privatefunctionfinishRequest(Request $request, int $type)void
{
$this->dispatcher->dispatch(
new FinishRequestEvent($this, $request, $type), 
        KernelEvents::FINISH_REQUEST
    );
}

异常处理

privatefunctionhandleThrowable(\Throwable $e, Request $request, int $type)Response
{
// 触发 kernel.exception 事件
    $event = new ExceptionEvent($this, $request, $type, $e);
$this->dispatcher->dispatch($event, KernelEvents::EXCEPTION);

// 获取异常响应
    $e = $event->getThrowable();

if (!$event->hasResponse()) {
// 没有监听器处理,重新抛出
throw $e;
    }

    $response = $event->getResponse();

// 设置异常状态码
if (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
if ($e instanceof HttpExceptionInterface) {
            $response->setStatusCode($e->getStatusCode());
            $response->headers->add($e->getHeaders());
        } else {
            $response->setStatusCode(500);
        }
    }

return$this->filterResponse($response, $request, $type);
}

子请求

HttpKernel 支持子请求(Sub-Request)。

// 主请求
$response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);

// 子请求(用于 ESI、内部转发等)
$subRequest = Request::create('/api/users');
$subResponse = $kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);

子请求的应用

// 控制器中转发
classUserController
{
publicfunction__construct(private HttpKernelInterface $kernel){}

publicfunctionshow(int $id)Response
{
// 内部转发到另一个控制器
        $subRequest = Request::create("/api/users/{$id}");
return$this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
    }
}

终止阶段

// Symfony\Component\HttpKernel\HttpKernel

publicfunctionterminate(Request $request, Response $response)void
{
$this->dispatcher->dispatch(
new TerminateEvent($this, $request, $response),
        KernelEvents::TERMINATE
    );
}

终止监听器

classSlowLogListener
{
publicfunctiononKernelTerminate(TerminateEvent $event)void
{
        $request = $event->getRequest();
        $startTime = $request->server->get('REQUEST_TIME_FLOAT');
        $duration = microtime(true) - $startTime;

if ($duration > 1.0) {
// 记录慢请求
$this->logger->warning('Slow request', [
'path' => $request->getPathInfo(),
'duration' => $duration,
            ]);
        }
    }
}

与 Laravel 的关系

Laravel 的 HTTP 层基于 Symfony HttpKernel 构建。

// Laravel 使用 Symfony 的 Request 和 Response
useSymfony\Component\HttpFoundation\Request;
useSymfony\Component\HttpFoundation\Response;

// Laravel 的 Kernel 实现了 Symfony 的接口
classKernelimplementsHttpKernelContract
{
publicfunctionhandle($request)
{
// 类似 Symfony 的处理流程
// 但使用 Laravel 的中间件管道
    }
}

自定义 HttpKernel

useSymfony\Component\HttpKernel\HttpKernel;
useSymfony\Component\HttpKernel\Controller\ControllerResolver;
useSymfony\Component\HttpKernel\Controller\ArgumentResolver;
useSymfony\Component\EventDispatcher\EventDispatcher;

// 创建事件调度器
$dispatcher = new EventDispatcher();

// 添加监听器
$dispatcher->addListener(KernelEvents::REQUEST, function(RequestEvent $event){
// 请求处理
});

// 创建 HttpKernel
$kernel = new HttpKernel(
    $dispatcher,
new ControllerResolver(),
new RequestStack(),
new ArgumentResolver()
);

// 处理请求
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

总结

组件
职责
HttpKernel
协调请求处理流程
EventDispatcher
事件分发
ControllerResolver
解析控制器
ArgumentResolver
解析控制器参数

核心事件:

  1. kernel.request – 请求开始
  2. kernel.controller – 控制器解析后
  3. kernel.response – 响应发送前
  4. kernel.exception – 异常发生时
  5. kernel.terminate – 响应发送后

下一篇我们来聊 PHP 底层 Zval 结构。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » Symfony HttpKernel 源码:框架的心脏

评论 抢沙发

1 + 4 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮