内核

Testing Is Documentation

tests/Kernel/KernelTest.php内核 - 图1

QueryPHP 流程为入口接受 HTTP 请求,经过内核 kernel 传入请求,经过路由解析调用控制器执行业务,最后返回响应结果。

入口文件 www/index.php

  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of the your app package.
  5. *
  6. * The PHP Application For Code Poem For You.
  7. * (c) 2018-2099 http://yourdomian.com All rights reserved.
  8. *
  9. * For the full copyright and license information, please view the LICENSE
  10. * file that was distributed with this source code.
  11. */
  12. use Common\App\ExceptionRuntime;
  13. use Common\App\Kernel;
  14. use Leevel\Di\Container;
  15. use Leevel\Di\IContainer;
  16. use Leevel\Http\Request;
  17. use Leevel\Kernel\App;
  18. use Leevel\Kernel\IApp;
  19. use Leevel\Kernel\IExceptionRuntime;
  20. use Leevel\Kernel\IKernel;
  21. /**
  22. * ---------------------------------------------------------------
  23. * Composer
  24. * ---------------------------------------------------------------.
  25. *
  26. * 用于管理 PHP 依赖包
  27. */
  28. require __DIR__.'/../vendor/autoload.php';
  29. /**
  30. * ---------------------------------------------------------------
  31. * 创建应用
  32. * ---------------------------------------------------------------.
  33. *
  34. * 注册应用基础服务
  35. */
  36. $container = Container::singletons();
  37. $container->singleton(IContainer::class, $container);
  38. $container->singleton('app', new App($container, realpath(__DIR__.'/..')));
  39. $container->alias('app', [IApp::class, App::class]);
  40. $container->singleton(IKernel::class, Kernel::class);
  41. $container->singleton(IExceptionRuntime::class, ExceptionRuntime::class);
  42. /**
  43. * ---------------------------------------------------------------
  44. * 执行应用
  45. * ---------------------------------------------------------------.
  46. *
  47. * 根据内核调度请求返回响应
  48. */
  49. $kernel = $container->make(IKernel::class);
  50. $response = $kernel->handle($request = Request::createFromGlobals());
  51. $response->send();
  52. $kernel->terminate($request, $response);

内核通过 \Leevel\Kernel\Kernel 的 handle 方法来实现请求。

handle 原型

  1. # Leevel\Kernel\Kernel::handle
  2. /**
  3. * 响应 HTTP 请求.
  4. */
  5. public function handle(Request $request): Response;

Uses

  1. <?php
  2. use Error;
  3. use Exception;
  4. use Leevel\Di\Container;
  5. use Leevel\Di\IContainer;
  6. use Leevel\Http\JsonResponse;
  7. use Leevel\Http\Request;
  8. use Leevel\Kernel\App as Apps;
  9. use Leevel\Kernel\Exception\HttpException;
  10. use Leevel\Kernel\ExceptionRuntime;
  11. use Leevel\Kernel\IApp;
  12. use Leevel\Kernel\IExceptionRuntime;
  13. use Leevel\Kernel\IKernel;
  14. use Leevel\Kernel\Kernel;
  15. use Leevel\Log\ILog;
  16. use Leevel\Option\IOption;
  17. use Leevel\Router\IRouter;
  18. use Symfony\Component\HttpFoundation\Response;

基本使用

fixture 定义

Tests\Kernel\Kernel1

  1. namespace Tests\Kernel;
  2. class Kernel1 extends Kernel
  3. {
  4. public function bootstrap(): void
  5. {
  6. }
  7. }
  1. public function testBaseUse(bool $debug): void
  2. {
  3. $app = new AppKernel($container = new Container(), '');
  4. $container->instance('app', $app);
  5. $request = $this->createMock(Request::class);
  6. $response = $this->createMock(Response::class);
  7. $router = $this->createRouter($response);
  8. $this->createOption($container, $debug);
  9. $this->createLog($container);
  10. $this->createRuntime($container);
  11. $kernel = new Kernel1($app, $router);
  12. $this->assertInstanceof(IKernel::class, $kernel);
  13. $this->assertInstanceof(IApp::class, $kernel->getApp());
  14. $this->assertInstanceof(Response::class, $resultResponse = $kernel->handle($request));
  15. }

JSON 响应例子

  1. public function testWithResponseIsJson(): void
  2. {
  3. $app = new AppKernel($container = new Container(), '');
  4. $container->instance('app', $app);
  5. $request = $this->createMock(Request::class);
  6. $response = new JsonResponse(['foo' => 'bar']);
  7. $router = $this->createRouter($response);
  8. $this->createOption($container, true);
  9. $this->createLog($container);
  10. $this->createRuntime($container);
  11. $kernel = new Kernel1($app, $router);
  12. $this->assertInstanceof(IKernel::class, $kernel);
  13. $this->assertInstanceof(IApp::class, $kernel->getApp());
  14. $this->assertInstanceof(Response::class, $resultResponse = $kernel->handle($request));
  15. $this->assertSame('{"foo":"bar"}', $resultResponse->getContent());
  16. }

异常处理

路由抛出异常,返回异常响应。

  1. # Tests\Kernel\KernelTest::createRouterWithException
  2. protected function createRouterWithException(): IRouter
  3. {
  4. $request = $this->createMock(Request::class);
  5. $router = $this->createMock(IRouter::class);
  6. $router->method('dispatch')->will($this->throwException(new Exception('hello foo bar.')));
  7. return $router;
  8. }
  1. public function testRouterWillThrowException(): void
  2. {
  3. $app = new AppKernel($container = new Container(), '');
  4. $container->instance('app', $app);
  5. $request = $this->createMock(Request::class);
  6. $router = $this->createRouterWithException();
  7. $this->createOption($container, true);
  8. $this->createLog($container);
  9. $this->createRuntimeWithRender($container);
  10. $kernel = new Kernel1($app, $router);
  11. $this->assertInstanceof(IKernel::class, $kernel);
  12. $this->assertInstanceof(IApp::class, $kernel->getApp());
  13. $this->assertInstanceof(Response::class, $resultResponse = $kernel->handle($request));
  14. $this->assertStringContainsString('hello foo bar.', $resultResponse->getContent());
  15. $this->assertStringContainsString('<span>hello foo bar.</span>', $resultResponse->getContent());
  16. $this->assertStringContainsString('<span class="exc-title-primary">Exception</span>', $resultResponse->getContent());
  17. }

错误处理

路由出现错误,返回错误响应。

  1. # Tests\Kernel\KernelTest::createRouterWithError
  2. protected function createRouterWithError(): IRouter
  3. {
  4. $request = $this->createMock(Request::class);
  5. $router = $this->createMock(IRouter::class);
  6. $router->method('dispatch')->will($this->throwException(new Error('hello bar foo.')));
  7. return $router;
  8. }
  1. public function testRouterWillThrowError(): void
  2. {
  3. $app = new AppKernel($container = new Container(), '');
  4. $container->instance('app', $app);
  5. $request = $this->createMock(Request::class);
  6. $router = $this->createRouterWithError();
  7. $this->createOption($container, true);
  8. $this->createLog($container);
  9. $this->createRuntimeWithRender($container);
  10. $kernel = new Kernel1($app, $router);
  11. $this->assertInstanceof(IKernel::class, $kernel);
  12. $this->assertInstanceof(IApp::class, $kernel->getApp());
  13. $this->assertInstanceof(Response::class, $resultResponse = $kernel->handle($request));
  14. $this->assertStringContainsString('<span>hello bar foo.</span>', $resultResponse->getContent());
  15. $this->assertStringContainsString('<span class="exc-title-primary">ErrorException</span>', $resultResponse->getContent());
  16. }