看看官网加粗的一句话:
$app->get('/forbase', function ($request, $response, $args){
Example\Module\Base::instance()->init($request,$response);
return $response;
})->add(Example\MiddleWare\MyMiddleware::instance(Example\Module\Base::instance()));
这篇先解决:get是怎么加进去的。在随后的文章里依次解决:route是怎么被调用的;route Middleware是如何加进去的。
在App.php里有变量container。这个变量的类型是Slim\Container,而Slim\Container 继承 PimpleContainer ,据官网说这个Pimple是一个DI Container,这个还不了解。
public function __construct($container = [])
{
if (is_array($container)) {
$container = new Container($container);
}
if (!$container instanceof ContainerInterface) {
throw new InvalidArgumentException('Expected a ContainerInterface');
}
$this->container = $container;
}
class Container extends PimpleContainer implements ContainerInterface
{
/**
* Create new container
*
* @param array $values The parameters or objects.
*/
public function __construct(array $values = [])
{
parent::__construct($values); $userSettings = isset($values['settings']) ? $values['settings'] : [];
$this->registerDefaultServices($userSettings);
}
在Container构造方法中会注册相关的DefaultServices包括router,以后所有的route都存在于router中:
if (!isset($this['router'])) {
/**
* This service MUST return a SHARED instance
* of \Slim\Interfaces\RouterInterface.
*
* @return RouterInterface
*/
$this['router'] = function () {
return new Router;
};
}
这个$this['router']其实是调用了Pimple\Container中的 offsetSet()方法,因为Pimple\Container实现了ArrayAccess,因此$this['router']是可用的。
public function offsetSet($id, $value)
{
if (isset($this->frozen[$id])) {
throw new \RuntimeException(sprintf('Cannot override frozen service "%s".', $id));
} $this->values[$id] = $value;
$this->keys[$id] = true;
}
这样的所有默认设置都存放在values这个变量里,以后拿设置从values里拿就好了。
在app->get()时,APP类所做的工作:
一get()/post()函数接受route创建请求。二调用app->map();三调用router->map();四设置route的container和output buffer。
上代码:
/**
* Add GET route
*
* @param string $pattern The route URI pattern
* @param mixed $callable The route callback routine
*
* @return \Slim\Interfaces\RouteInterface
*/
public function get($pattern, $callable)
{
return $this->map(['GET'], $pattern, $callable);
}
public function map(array $methods, $pattern, $callable)
{
if ($callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
} $route = $this->container->get('router')->map($methods, $pattern, $callable);
if (is_callable([$route, 'setContainer'])) {
$route->setContainer($this->container);
} if (is_callable([$route, 'setOutputBuffering'])) {
$route->setOutputBuffering($this->container->get('settings')['outputBuffering']);
}
return $route;
}
同时router类所做的工作:
当有get、post之类的需要加入时,会在router中的map()方法中生成新的route并且给每个route进行了编号,将这个route加入到router的routes数组中。
上代码:
/**
* Add route
*
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable $handler The route callable
*
* @return RouteInterface
*
* @throws InvalidArgumentException if the route pattern isn't a string
*/
public function map($methods, $pattern, $handler)
{
if (!is_string($pattern)) {
throw new InvalidArgumentException('Route pattern must be a string');
} // Prepend parent group pattern(s)
if ($this->routeGroups) {
$pattern = $this->processGroups() . $pattern;
} // According to RFC methods are defined in uppercase (See RFC 7231)
$methods = array_map("strtoupper", $methods); // Add route
$route = new Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter);
$this->routes[$route->getIdentifier()] = $route;
$this->routeCounter++; return $route;
}
这样的一个过程之后,某个添加的route就放入到router的routes数组中了。再以后APP接收到请求后,会在routes选择合适的route来处理处理请求。