🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 中间件 [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(); } } ```