学习Slim Framework for PHP v3 --route怎么被匹配的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习Slim Framework for PHP v3 --route怎么被匹配的?相关的知识,希望对你有一定的参考价值。

  先标记觉得以后会用到的内容:

// add route to the request‘s attributes in case a middleware or handler needs access to the route
$request = $request->withAttribute(‘route‘, $route);

或许以后可以在Middleware中拿到route做些其他的事情。

  上篇已经分析到route是在APP的__invoke()中被调用的,这里来看看怎么匹配route的。大概的调用过程如下:

APP->__invoke()
     \
$request = $this->dispatchRouterAndPrepareRoute($request, $router);
     \
$routeInfo = $router->dispatch($request);
     \
$this->createDispatcher()->dispatch($request->getMethod(),$uri); (告知是否找到,并且给出route的id)
     \
\FastRoute\simpleDispatcher(function (RouteCollector $r){}) (将所有的route存放在RouteCollector中,并且返回GroupCountBased)
     \
foreach ($this->getRoutes() as $route) {
    $r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
 
  在APP __invoke里会去寻找匹配的route。route在router中,自然要去routers中去寻找,调用了 $router->dispatch($request)。在router的dispatch中会创建一个Dispatcher,$this->createDispatcher()。
  在createDispatcher()会使用一个命名空间公共函数\FastRoute\simpleDispatcher()。它将每个route的方法(get/post)、pattern、identify组成一个数组放入 RouteCollector 中,再通过GroupCountBased的构造方法将RouteCollector的数据都传入GroupCountBased。$this->createDispatcher()->dispatch($request->getMethod(),$uri)的dispatch其实是GroupCountBased的dispatch()方法。
  GroupCountBased->dispatch($request->getMethod(),$uri)会匹配相应的route。这匹配的办法其实很简单,就是判断所传入的method与uri是否在数组中能取到($this->staticRouteMap[$httpMethod][$uri])。返回匹配到与否的标志、route的identify。
  App->dispatchRouterAndPrepareRoute()会将返回的route匹配结果保留并存入到requst 中,这样以后再request中就直接可以拿到对应的route了,想起来棒棒的,但是肿么拿呢。
  APP->__invoke()执行进行route的执行:
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]);
        }

  $route = $router->lookupRoute($routeInfo[1]); 通过route的identify找到route。

  route->run执行route。

  run的结果最后就是执行自己的__invoke,从所有的middleware开始执行,栈的最后一个元素是自己。

    /**
     * Dispatch route callable against current Request and Response objects
     *
     * This method invokes the route object‘s callable. If middleware is
     * registered for the route, each callable middleware is invoked in
     * the order specified.
     *
     * @param ServerRequestInterface $request  The current Request object
     * @param ResponseInterface      $response The current Response object
     * @return \Psr\Http\Message\ResponseInterface
     * @throws \Exception  if the route callable throws an exception
     */
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
    {
        //debug_print_backtrace();
        $this->callable = $this->resolveCallable($this->callable);

        /** @var InvocationStrategyInterface $handler */
        $handler = isset($this->container) ? $this->container->get(‘foundHandler‘) : new RequestResponse();

        // invoke route callable
        if ($this->outputBuffering === false) {
            $newResponse = $handler($this->callable, $request, $response, $this->arguments);
        } else {
            try {
                ob_start();
                $newResponse = $handler($this->callable, $request, $response, $this->arguments);
                $output = ob_get_clean();
            } catch (Exception $e) {
                ob_end_clean();
                throw $e;
            }
        }

        if ($newResponse instanceof ResponseInterface) {
            // if route callback returns a ResponseInterface, then use it
            $response = $newResponse;
        } elseif (is_string($newResponse)) {
            // if route callback returns a string, then append it to the response
            if ($response->getBody()->isWritable()) {
                $response->getBody()->write($newResponse);
            }
        }

        if (!empty($output) && $response->getBody()->isWritable()) {
            if ($this->outputBuffering === ‘prepend‘) {
                // prepend output buffer content
                $body = new Http\Body(fopen(‘php://temp‘, ‘r+‘));
                $body->write($output . $response->getBody());
                $response = $response->withBody($body);
            } elseif ($this->outputBuffering === ‘append‘) {
                // append output buffer content
                $response->getBody()->write($output);
            }
        }

        return $response;
    }
  $this->callable = $this->resolveCallable($this->callable);用来将class::method的callback组成正常的callback。
  $handler 是找到的策略,在handler会执行 call_user_func(),也就是route的闭包函数被执行了,也就是route此时被执行。 这样将得到reponse返回或者将得到的字符串结果写入网页中。
 

以上是关于学习Slim Framework for PHP v3 --route怎么被匹配的?的主要内容,如果未能解决你的问题,请参考以下文章

学习Slim Framework for PHP v3

学习Slim Framework for PHP v3 --route怎么被调用的?

学习Slim Framework for PHP v3 --route怎么被匹配的?

PHP Slim 3 Framework - 我可以在哪里放置我的控制器文件?

PHP Slim Framework REST API - 在每条路由之前验证访问令牌?

Slim Framework和Ember.js中的Access-Control-Origin