## 中间件的载入
中间件主要用于拦截或过滤应用的http请求,并进行必要的业务处理。
默认的中间件类文件的命名空间是app\http\middleware。可以通过配置文件配置属性`default_namespace`,来设置。在app类中是通过应用的初始化,来加载中间件的配置文件。应用中间件的配置文件在应用目录下`middleware.php`。模块中间件的配置文件在模块目录下的`middleware.php` ;
```
if (is_file($path . 'middleware.php')) {
$middleware = include $path . 'middleware.php';
if (is_array($middleware)) {
$this->middleware->import($middleware);
}
}
```
middleware类是通过import方法导入中间件,import方法在通过循环调用add方法将中间件注册到middleware类的$queue的数组中。
```
public function add($middleware, $type = 'route')
{
if (is_null($middleware)) {
return;
}
// 调用buildMiddleware方法进行中间件的解析
$middleware = $this->buildMiddleware($middleware, $type);
if ($middleware) {
$this->queue[$type][] = $middleware;
}
}
```
在buildMiddleware方法中,进行中间件的解析和拼装。
```
protected function buildMiddleware($middleware, $type = 'route')
{
if (is_array($middleware)) {
list($middleware, $param) = $middleware;
}
// 若是闭包中间件 则返回数组 [闭包函数,数组]
if ($middleware instanceof \Closure) {
return [$middleware, isset($param) ? $param : null];
}
if (!is_string($middleware)) {
throw new InvalidArgumentException('The middleware is invalid');
}
// $middleware 中不包含 \\ 符号
if (false === strpos($middleware, '\\')) {
if (isset($this->config[$middleware])) {
$middleware = $this->config[$middleware];
} else {
$middleware = $this->config['default_namespace'] . $middleware;
}
}
if (is_array($middleware)) {
return $this->import($middleware, $type);
}
if (strpos($middleware, ':')) {
list($middleware, $param) = explode(':', $middleware, 2);
}
// 找到中间件所对应的类,并进行实例化。
// 最终返回 [[中间件实例, 'handle'], 参数]。
$middleware_item = [[$this->app->make($middleware), 'handle'], isset($param) ? $param : null];
return $middleware_item;
}
```
## 中间件的调度
在app类中,通过调用middleware类的dispatch方法,进行中间件的调度。dispatch方法通过使用php内置函数`call_user_func`调用resolve方法。
resolve方法返回一个匿名函数。匿名函数先取出$queue数组中第一个中间件,然后通过php内置函数call_user_func_array调用中间件中的handle方法。(handle函数的第二个参数也是传入resolve方法的匿名函数)。
```
protected function resolve($type = 'route')
{
return function (Request $request) use ($type) {
$middleware = array_shift($this->queue[$type]);
if (null === $middleware) {
throw new InvalidArgumentException('The queue was exhausted, with no response returned');
}
list($call, $param) = $middleware;
try {
$response = call_user_func_array($call, [$request, $this->resolve($type), $param]);
} catch (HttpResponseException $exception) {
$response = $exception->getResponse();
}
if (!$response instanceof Response) {
throw new LogicException('The middleware must return Response instance');
}
return $response;
};
}
```
在中间件类的handle 方法中,必须要返回一个response对象。
```
public function handle($request, \Closure $next)
{
echo "action";
$response = $next($request);
echo "end";
return $response;
}
```