# 中间件
[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();
}
}
```