# 中間件
[TOC]
## 簡單描述
這里的中間件其實跟HOOK的功能是有點類似的,定義一連串的操作來執行某一項處理,使用中間件主要是對請求進行攔截,方便把一些業務處理分隔開方便管理。
## HOOK和中間件區別
1. 中間件是鏈式執行的,上一個中間件執行完畢主動調用下一個中間件,如果不調用就會中斷,全部執行完后返回最后一個中間件的執行結果
2. HOOK是串連一些操作如果上一個操作返回`false`則中斷執行,如果所有操作都不返回`false`,則會執行完所有操作后返回一個結果數組
中間件的入口執行方法默認是`handle`方法,而且第一個參數是`Request`對象,第二個參數是一個閉包。
中間件的命令空間沒有強制要求,但建議和框架的命名空間保持一至,命名規則為 **middleware/模塊/中間件名字**,
## 中間件定義
定義一個中間件數組,單個中間件的格式如下
* [[中間件類,方法],[參數,參數]]
* [閉包/函數/靜態方法,[參數,參數]]
數組的長度最多兩個,
第一個是【中間件類,方法】或【閉包/函數/靜態方法】,
第二個是【參數1,參數2】會做為參數傳入中間件的方法中,
第三個 **bool** 值 ,標識如果是類的話是否創建新的實例,默認為false不創建,這一次請求中如果一個中間件會被多次調用的話,這個參數可以避免重復使用帶來的一些問題
>第一個為中間件類(默認調用 handle,如果是個數組,則第二個參數為類或函數的方法,第二個往后以次為要輸入的參數,第一個如果只是一個類名的話也可以傳字符串,默認會調用handle方法,
### 參數傳遞規則
* 第一個參數為request對象, 第二個參數為閉包回調(\Closure $next),固定不變
* 從三個參數開始依次傳入中間件調度時傳入的參數,如果dispatch有參數則會優先從第三個函數插入,然后中間件中定義的參數才會依次插入傳遞
*
## 單獨使用方法
``` php
// 要過濾的數據
$data=[
‘name’=>'名字',
'mobile'=>'16600000000',
'money'=>1000
];
$midlist=[
[[\middleware\index\Search::class], ['nameasdfasf']],
//沒有參數就直接寫類名
[[\middleware\index\Second::class],[]]
];
// 實例化要執行中間的對象
$middleware = new Middleware();
// 導入中間件列表
$middleware->import($midlist);
// 添加一個中間件
//$middleware->add( [[\middleware\index\Second::class],[]]
);
// 調度中間件執行
$moddleware->dispatch(&$data);
// 最后使用data
```
## 控制器中使用中間件
### 業務場景
中間件主要用于,把數據攔截過來進行處理然后再放行或直接返回響應結果,例如有一個數組,最終目的是要輸出的,可以在輸出之前定義一組中間件(總監->財務->銷售總監->組長->業務員),數據會按這個順序依次傳引用進入中間件中處理,最終才會顯示。
如果以后有一個職位取消的話直接刪除這個中間件就可以,不會對原有流程有影響
### 調用流程
在執行控制器的方法前,會先執行下面方法來確定此方法是否注冊有中間件,調用中間件進行處理
``` php
public function runActionMiddleware(string $action)
{
if ($this->middleware
&& isset($this->middleware[$action])
&& is_array($this->middleware[$action])) {
$this->app->get('middleware')
->import($this->middleware[$action])
->dispatch();
}
}
```
### 中間件類定義
``` php
namespace middleware\index;
use ank\Request;
/**
*搜索關鍵詞過濾
*/
class Search
{
public function handle(Request $request, \Closure $next, $name)
{
$request->testkey = 'testkey' . $name;
// return \ank\Response::create([], 'json');
//執行下一個中間件
return $next();
}
}
```
處理后要返回 $next($request) 業務會將數據傳遞給其它中間件處理,如果返回的是Response實例則會直接響應客戶端,handle的參數根據自己的需要可以傳引用數據
### 控制器中注冊中間件
然后在控制器中添加middleware屬性,數組里的鍵為當前控制器中方法的名字,一定要跟方法一至(區分大小寫),如下所示在**index**操作方法被調用前會先執行中間件中的操作對請求進行過濾設置
``` php
namespace controller\index;
use ank\App;
/**
* asdf
*/
class Index extends \ank\Controller
{
protected $middleware = [
'index' => [
// 第一個為中間件類,第二個往后以次為要輸入的參數
[\middleware\index\Search::class, 'nameasdfasf'],
//沒有參數就直接寫類名
\middleware\index\Second::class,
],
];
public function index()
{
// echo input('testkey');
$app = App::getInstance();
$runtime = number_format(microtime(true) - $app->getStartTime(), 10);
echo $runtime;
die();
}
}
```