美文网首页
slim3 Request请求流程解析

slim3 Request请求流程解析

作者: yates_txw | 来源:发表于2018-05-15 19:05 被阅读0次

1、首先我们先来看看slim的run方法

public function run($silent = false)
{
      $response = $this->container->get('response');

      try {
          ob_start();
          $response = $this->process($this->container->get('request'), $response);
      } catch (InvalidMethodException $e) {
          $response = $this->processInvalidMethod($e->getRequest(), $response);
      } finally {
          $output = ob_get_clean();
      }

      // ....
      // ....
}

其中$this->container->get('request')回去回去一个注册的request对象

// 在框架初始化时注册
if (!isset($container['request'])) { 
      $container['request'] = function ($container) {
          return Request::createFromEnvironment($container->get('environment'))
      };
 }


public function get($id)
{
    // ...
    // ...

    try {
        return $this->offsetGet($id);
    } catch (\InvalidArgumentException $exception) {
       // ...
       // ...
       // ...
    }
}


public function offsetGet($id)
{
    if (!isset($this->keys[$id])) {
        throw new UnknownIdentifierException($id);
    }

    if (
        isset($this->raw[$id])
        || !\is_object($this->values[$id])
        || isset($this->protected[$this->values[$id]])
        || !\method_exists($this->values[$id], '__invoke')
    ) {
        return $this->values[$id];
    }

    if (isset($this->factories[$this->values[$id]])) {
        return $this->values[$id]($this);
    }

    $raw = $this->values[$id];
    $val = $this->values[$id] = $raw($this);
    $this->raw[$id] = $raw;

    $this->frozen[$id] = true;

    return $val;
}

框架初始化时会判断request有没有被设置,没有则会将一个方法赋值给container的request对象,而container的get方法最终会通过offsetGet()方法去获取,这里提一个container实现了ArrayAccess 接口,这个实现的好处就是可以像数组一样去访问对象。

我们重点来看一下offsetGet()方法,上面的几个if我们放到最后看,先看下面的赋值。$this->values['request']就是我们最开始那个注册的方法,我们将它赋值给$raw, 然后在执行这个方法将返回值赋值给 $val与$this->values['request'],在将$raw放到$this->raw['request'],然后将$this->frozen['request']设置为true,说明这个id已经初始化完成了。

这时候我们再反过来查看上面的if方法,

  • isset($this->raw[$id])判断$this->raw中是否设置过该id
  • !\is_object($this->values[$id])判断是否是个对象,
  • !\method_exists($this->values[$id], '__invoke')判断对象中是否存在__invoke方法,即不能直接调用
  • isset($this->protected[$this->values[$id]]) 是否需要将方法当做参数,不执行直接返回
  • isset($this->factories[$this->values[$id]])是否是一个可直接调用的callable

即如果$this->values[$id]有如下情况,就会直接返回

  • 是一个对象
  • 之前调用过
  • 设置了保护,需要直接返回callable
  • 不可调用的对象实例
  • 设置了factories

经过上面的步骤,我们得到了request对象,接下来进入process()方法

public function process(ServerRequestInterface $request, ResponseInterface $response)
{
    // ...
    // ...
    try {
        $response = $this->callMiddlewareStack($request, $response);
    } catch (Exception $e) {
        $response = $this->handleException($e, $request, $response);
    } catch (Throwable $e) {
        $response = $this->handlePhpError($e, $request, $response);
    }

    return $response;
}

public function callMiddlewareStack(ServerRequestInterface $request, ResponseInterface $response)
{
    if (is_null($this->tip)) {
        $this->seedMiddlewareStack();
    }
    /** @var callable $start */
    $start = $this->tip;
    $this->middlewareLock = true;
    $response = $start($request, $response);
    $this->middlewareLock = false;
    return $response;
}

protected function seedMiddlewareStack(callable $kernel = null)
{
    if (!is_null($this->tip)) {
        throw new RuntimeException('MiddlewareStack can only be seeded once.');
    }
    if ($kernel === null) {
        $kernel = $this;
    }
    $this->tip = $kernel;
}

这里我们就主要看看 $this->callMiddlewareStack($request, $response)这个方法就ok。开始时现将$this即app对象赋值给$this->tip,然后将$this->tip 赋值给$start, 接着以调用函数的方法调用对象,运行app的__invoke方法。

public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
{
    // Get the route info
    $routeInfo = $request->getAttribute('routeInfo');

    /** @var \Slim\Interfaces\RouterInterface $router */
    $router = $this->container->get('router');

    // If router hasn't been dispatched or the URI changed then dispatch
    if (null === $routeInfo || ($routeInfo['request'] !== [$request->getMethod(), (string) $request->getUri()])) {
        $request = $this->dispatchRouterAndPrepareRoute($request, $router);
        $routeInfo = $request->getAttribute('routeInfo');
    }

    // 找到匹配的路由
    if ($routeInfo[0] === Dispatcher::FOUND) {
        $route = $router->lookupRoute($routeInfo[1]);
        return $route->run($request, $response);
    } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
        // 方法不允许访问
        if (!$this->container->has('notAllowedHandler')) {
            throw new MethodNotAllowedException($request, $response, $routeInfo[1]);
        }
        /** @var callable $notAllowedHandler */
        $notAllowedHandler = $this->container->get('notAllowedHandler');
        return $notAllowedHandler($request, $response, $routeInfo[1]);
    }

    // 没有找到对应的处理
    if (!$this->container->has('notFoundHandler')) {
        throw new NotFoundException($request, $response);
    }
    /** @var callable $notFoundHandler */
    $notFoundHandler = $this->container->get('notFoundHandler');
    return $notFoundHandler($request, $response);
}

在__invoke中,分为三种情况

  • 找到匹配的路由,执行对应方法
  • 方法不允许访问,判断有没有注册notAllowedHandler,注册就用该handle处理,没有则报异常
  • 没有找到对应路由,判断有没有注册notFoundHandler,注册就用该handle处理,没有则报异常

相关文章

网友评论

      本文标题:slim3 Request请求流程解析

      本文链接:https://www.haomeiwen.com/subject/matsdftx.html