接上节。
$app->router->group([
'namespace' => 'App\Http\Controllers',
], function ($router) {
require __DIR__.'/../routes/web.php';
});
$app->router 上节讲到是 Router.php
public function group(array $attributes, \Closure $callback)
{
if (isset($attributes['middleware']) && is_string($attributes['middleware'])) {
$attributes['middleware'] = explode('|', $attributes['middleware']);
}
$this->updateGroupStack($attributes);
call_user_func($callback, $this);
array_pop($this->groupStack);
}
看到
call_user_func($callback, $this);
即引入 web.php 路由文件,接下来调用 get post等方法,将路由绑定在 $this->routes 变量
接下来看到
$app->run();
此处有个知识点,app是 Application.php类,不存在run方法,从何来?使用了语法糖,RoutesRequests有run方法
use Concerns\RoutesRequests,
Concerns\RegistersExceptionHandlers;
接下来看到 run()方法
public function run($request = null)
{
$response = $this->dispatch($request);
if ($response instanceof SymfonyResponse) {
$response->send();
} else {
echo (string) $response;
}
if (count($this->middleware) > 0) {
$this->callTerminableMiddleware($response);
}
}
先看
$response = $this->dispatch($request);
public function dispatch($request = null)
{
list($method, $pathInfo) = $this->parseIncomingRequest($request);
try {
return $this->sendThroughPipeline($this->middleware, function () use ($method, $pathInfo) {
if (isset($this->router->getRoutes()[$method.$pathInfo])) {
return $this->handleFoundRoute([true, $this->router->getRoutes()[$method.$pathInfo]['action'], []]);
}
return $this->handleDispatcherResponse(
$this->createDispatcher()->dispatch($method, $pathInfo)
);
});
} catch (Exception $e) {
return $this->prepareResponse($this->sendExceptionToHandler($e));
} catch (Throwable $e) {
return $this->prepareResponse($this->sendExceptionToHandler($e));
}
}
看向 $this->parseIncomingRequest($request) 这里返回的是 对 $_GET $_POST 之类的封装,不赘述。
protected function parseIncomingRequest($request)
{
if (! $request) {
$request = Request::capture();
}
$this->instance(Request::class, $this->prepareRequest($request));
return [$request->getMethod(), '/'.trim($request->getPathInfo(), '/')];
}
回到上步,看向 sendThroughPipeline(),此处的 middleware是空,直接 执行$then()
protected function sendThroughPipeline(array $middleware, Closure $then)
{
if (count($middleware) > 0 && ! $this->shouldSkipMiddleware()) {
return (new Pipeline($this))
->send($this->make('request'))
->through($middleware)
->then($then);
}
return $then();
}
执行then()
function () use ($method, $pathInfo) {
if (isset($this->router->getRoutes()[$method.$pathInfo])) {
return $this->handleFoundRoute([true, $this->router->getRoutes()[$method.$pathInfo]['action'], []]);
}
return $this->handleDispatcherResponse(
$this->createDispatcher()->dispatch($method, $pathInfo)
);
}
//此处返回的是 $this->routes的数组 判断本次请求是否在配置的路由内,这里只考虑在的情况
$this->router->getRoutes()[$method.$pathInfo]
进入
$this->handleFoundRoute([true, $this->router->getRoutes()[$method.$pathInfo]['action'], []]);
protected function handleFoundRoute($routeInfo)
{
$this->currentRoute = $routeInfo;
$this['request']->setRouteResolver(function () {
return $this->currentRoute;
});
$action = $routeInfo[1];
// Pipe through route middleware...
if (isset($action['middleware'])) {
$middleware = $this->gatherMiddlewareClassNames($action['middleware']);
return $this->prepareResponse($this->sendThroughPipeline($middleware, function () {
return $this->callActionOnArrayBasedRoute($this['request']->route());
}));
}
return $this->prepareResponse(
$this->callActionOnArrayBasedRoute($routeInfo)
);
}
这里有个知识点,$this['request']是什么?
Application implements ArrayAccess
继承ArrayAccess,相当于访问 offsetGet('request')
public function offsetGet($key)
{
return $this->make($key);
}
接下来看到
if (isset($action['middleware'])) {
//返回中间件,不展开讲解
$middleware = $this->gatherMiddlewareClassNames($action['middleware']);
return $this->prepareResponse($this->sendThroughPipeline($middleware, function () {
return $this->callActionOnArrayBasedRoute($this['request']->route());
}));
}
看到
$this->sendThroughPipeline($middleware, function () {
return $this->callActionOnArrayBasedRoute($this['request']->route());
})
protected function sendThroughPipeline(array $middleware, Closure $then)
{
if (count($middleware) > 0 && ! $this->shouldSkipMiddleware()) {
return (new Pipeline($this))
->send($this->make('request'))
->through($middleware)
->then($then);
}
return $then();
}
public function send($passable)
{
$this->passable = $passable;
return $this;
}
public function through($pipes)
{
$this->pipes = is_array($pipes) ? $pipes : func_get_args();
return $this;
}
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
这里的then方法是重点,大意就是将循环 $this->prepareDestination($destination) 和 array_reverse($this->pipes) 放到 $this->carry() 里,也就是将请求放在所有中间件中过一遍。
最后执行
function () {
return $this->callActionOnArrayBasedRoute($this['request']->route());
}
下面就是实例化具体的类了,不展开讲。
有个细节,怎么讲Request $request 注入到每个方法里,这里在调用方法前,有个make的细节,于是每个方法里就可以通过$request来获取参数了
protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null)
{
$segments = explode('@', $target);
// We will assume an @ sign is used to delimit the class name from the method
// name. We will split on this @ sign and then build a callable array that
// we can pass right back into the "call" method for dependency binding.
$method = count($segments) == 2
? $segments[1] : $defaultMethod;
if (is_null($method)) {
throw new InvalidArgumentException('Method not provided.');
}
return static::call(
$container, [$container->make($segments[0]), $method], $parameters
);
}