如何处理http请求?

上一篇文章我们讲了thinkphp的容器的实现过程,也知道了http实例的获取来源,接下来就是http开始处理请求了,看代码:

$response = $http->run();

对!你没看错!就这么一行代码!
当然,只是这一行代码肯定没办法处理整个请求逻辑,我们看这行代码之后具体做了什么操作,我们进入Http类,找到run()这个方法:

/**
 * 执行应用程序
 * @access public
 * @param Request|null $request
 * @return Response
 */
public function run(Request $request = null): Response
{
  //自动创建request对象
  $request = $request ?? $this->app->make('request', [], true);
  $this->app->instance('request', $request);

  try {
    $response = $this->runWithRequest($request);
  } catch (Throwable $e) {
    $this->reportException($e);

    $response = $this->renderException($request, $e);
  }

  return $response;
}

处理http请求的核心部分

我们看第一行,上一篇文章我们已经分析过make()是如何运行的了,那这行代码我们也就很容易能理解了,这是获取了一个Request类的实例。
然后第二行,我们也分析过instance()这个方法,就是把实例绑定到容器的,也就是说,程序执行到这里的时候,我们的容器里就存入了Request类。
我们继续往下看try中的这行代码:$response = $this->runWithRequest($request);,这行代码调用了runWithRequest()这个方法,我们看一下这个方法的具体代码:

/**
 * 执行应用程序
 * @param Request $request
 * @return mixed
 */
protected function runWithRequest(Request $request)
{
  // 1.调用App类的初始化$this->app->initialize();
  $this->initialize();
  // 2.加载全局中间件
  $this->loadMiddleware();

  // 3.监听HttpRun
  $this->app->event->trigger(HttpRun::class);
  
  return $this->app->middleware->pipeline()// 4.处理中间件的调度,仔细分析middleware类中的pipeline()方法会发现,这一步会执行中间件
    ->send($request)// 5.把包含请求数据的$request类初始化进当前执行
    ->then(function ($request) {
      return $this->dispatchToRoute($request);// 6.开始处理路由调度,根据路由找到具体要执行的文件位置:控制器、方法等,执行并返回结果
    });
}

上面这个方法就是执行应用程序的具体过程,下面我们会一点一点来分析上面注释中的各个点。

1、注释1:调用App类的初始化

我们找到它调用的App中的方法,看代码:

/**
 * 初始化应用
 * @access public
 * @return $this
 */
public function initialize()
{
  $this->initialized = true;
  $this->beginTime = microtime(true);
  $this->beginMem  = memory_get_usage();
  // 加载环境变量
  if (is_file($this->rootPath . '.env')) {
    $this->env->load($this->rootPath . '.env');
  }
  $this->configExt = $this->env->get('config_ext', '.php');
  $this->debugModeInit();
  // 加载全局初始化文件
  $this->load();
  // 加载框架默认语言包
  $langSet = $this->lang->defaultLangSet();
  $this->lang->load($this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $langSet . '.php');
  // 加载应用默认语言包
  $this->loadLangPack($langSet);
  // 监听AppInit
  $this->event->trigger(AppInit::class);
  date_default_timezone_set($this->config->get('app.default_timezone', 'Asia/Shanghai'));
  // 初始化
  foreach ($this->initializers as $initializer) {
    $this->make($initializer)->init($this);
  }
  return $this;
}
2、注释2:加载全局中间件
3、注释3:监听HttpRun
4、注释4:处理中间件的调度
5、注释5:初始化当前执行的数据
6、注释6:处理路由调度

--未完待续--