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

// 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怎么被匹配的?的更多相关文章

  1. 学习Slim Framework for PHP v3 (五)--route怎么被调用的?

    上一篇中分析了get()如何加入新的route的,这篇来分析route是如何被调用的. 首先,route是在routers里保存,router有在container中存放.container提供了ge ...

  2. 学习Slim Framework for PHP v3 (七)--route middleware怎么被add进来的?

    上两篇中分析了route是怎么被加进来的,以及如何被匹配的.这篇说一下route middleware是如何被加进来的,即add进来的.index.php的代码如下: $app->get('/f ...

  3. 学习Slim Framework for PHP v3 (四)--get()是怎么加进去的?

    看看官网加粗的一句话: At its core, Slim is a dispatcher that receives an HTTP request, invokes an appropriate ...

  4. 学习Slim Framework for PHP v3 (三)

    继续上一篇的问题,如何动态的添加不同的Module.添加Module是给Middleware用的,用于调用Module的写日志方法.上篇中的写法是在app->add(mv),这时的middlew ...

  5. 学习Slim Framework for PHP v3 ( 二)

    昨天说到能够成功将本地的URL通过在index.php 中添加get(pattern,clouser)路由到指定的处理类中,处理后(这里指存入数据库中),然后返回response在浏览器中显示. 昨天 ...

  6. Migration from Zend Framework v2 to v3

    Migration from Zend Framework v2 to v3 Zend Framework v2 to v3 has been intended as an incremental u ...

  7. 快乐学习 Ionic Framework+PhoneGap 手册1-1{创建APP项目}

    快乐学习 Ionic Framework+PhoneGap 手册1-1 * 前提必须安装 Node.js,安装PhoneGap,搭建Android开发环境,建议使用真机调试 {1.1}= 创建APP项 ...

  8. 学习Entity Framework 中的Code First

    这是上周就写好的文章,是在公司浩哥的建议下写的,本来是部门里面分享求创新用的,这里贴出来分享给大家. 最近在对MVC的学习过程中,接触到了Code First这种新的设计模式,感觉很新颖,并且也体验到 ...

  9. 转载:学习Entity Framework 中的Code First

    看完觉得不错,适合作为学习资料,就转载过来了 原文链接:http://www.cnblogs.com/Wayou/archive/2012/09/20/EF_CodeFirst.html 这是上周就写 ...

随机推荐

  1. fastJson泛型如何转换

    引子 现在负责的业务 和 json 打交道比较多, 最近使用fastJson框架 json串转成泛型对象遇到了一个异常 : java.lang.ClassCastException 还原下场景 : 模 ...

  2. extjs 点击复选框在表格中增加相关信息行

    功能效果:点击复选框在表格中自动增加相关信息行,复选框取消则表格中内容自动删除 初始效果大概是这样~~~~~ // 定义初始 存放表格数据 var gridItems = []; //省份复选框 va ...

  3. 71道经典Android面试题和答案

    ,,面试题1.        下列哪些语句关于内存回收的说明是正确的? (b ) A. 程序员必须创建一个线程来释放内存  B.内存回收程序负责释放无用内存   C.内存回收程序允许程序员直接释放内存 ...

  4. sc7731 Android 5.1 Camera 学习之一Camera 两个对象

    众所周知,在Android中Camera采用了C/S架构,其中Camera server 与 Camera client之间通过Android Binder IPC机制进行通信.在Camera实现的框 ...

  5. SCCM2012分发脚本

    1.分发批处理脚本 命令行:script.bat 2.分发PowerShell脚本 命令行:PowerShell.exe -executionpolicy unrestricted -file .\s ...

  6. 一次JQuery性能优化实战

    同事写了段JQuey的代码,在某些机器上,会出现IE假死的性能问题. 我测试了一下代码花费的时间,在我的机器上,会花费600多毫秒,但在某些机器上会花费6秒多(10倍的增长),这样就导致了IE的假死. ...

  7. 如何在C#中使用全局鼠标、键盘Hook

    今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全 ...

  8. 点击次数(thinkphp)

    protected function addHit($tbName, $id) { //定义变量:作为一个查询条件 $where = array( 'deleted' => 0, 'hidden ...

  9. C++11 之for 新解

     前言     C++11这次的更新带来了令非常多C++程序猿期待已久的for range循环,每次看到javascript. lua里的for range.心想要是C++能有多好,心里别提多酸了.这 ...

  10. Map生成器 map适配器如今能够使用各种不同的Generator,iterator和常量值的组合来填充Map初始化对象

    Map生成器 map适配器如今能够使用各种不同的Generator,iterator和常量值的组合来填充Map初始化对象 package org.rui.collection2.map; /** * ...