## 中間件的載入
中間件主要用于攔截或過濾應用的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;
}
```