PHP中间件(middleware)解析

来源:互联网 发布:简单 三维建模软件 编辑:程序博客网 时间:2024/05/16 14:02

笔者在研读guzzlehttp源码时,对中间件的使用研究了一翻,在此纪录学习笔记。

我的理解

在执行主要逻辑时,完成一些附带的逻辑,可以分为前置和后置中间件。附带的逻辑往往带有条件判断,比如验证是否有权限,判断配置信息从而做出相应操作。目的是使各个业务逻辑更清晰、独立、可拆卸。

举例

// 主要逻辑$meet = function($name){    echo "nice to meet you, $name \n";};// 前置中间件$hello = function($handler){    return function($name)use($handler){        echo "hello ".$name.", may I have your name\n";        $name = 'Lucy';        return $handler($name);    };};// 前置中间件$weather = function($handler){    return function($name)use($handler){        echo 'what a day'."\n";        return $handler($name); // weather_return_handler行    };};// 后置中间件$dinner = function($handler){    return function($name)use($handler){        $return = $handler($name);        $name = 'Lucy';        echo "OK, $name. Will you have dinner with me?\n";        return $return;    };};// 中间件栈$stack = [];// 打包function prepare($handler, $stack){    foreach(array_reverse($stack) as $key => $fn){        // echo $key; 记为echo_key行        $handler = $fn($handler); // 记为iterator行    }    return $handler;}// 入栈$stack['dinner'] = $dinner;$stack['weather'] = $weather;$stack['hello'] = $hello;// 把所有逻辑打包成一个闭包(closure)$run = prepare($meet, $stack);$run('beauty'); // 记为run_prepare/* 执行结果:what a dayhello beauty, may I have your namenice to meet you, Lucy OK, Lucy. Will you have dinner with me?*/

编写规范

中间件要要满足一定的规范:总是返回一个闭包,闭包中总是传入相同的参数(由主要逻辑决定), 闭包总是返回句柄(handler)的执行结果;

如果中间件的逻辑在返回句柄return $handler($name)前完成,就是前置中间件,否则为后置。这只是一个代码规范,你完全可以在一个中间件中的任何位置写逻辑代码,只要在最后正确返回。

打包程序

中间件的执行顺序是由打包函数(prepare)决定,这里是先入栈先执行,比如weather比hello先执行。

打包函数是一个这里有趣的地方。如果把prepare函数中的echo_key行 注释打开,会发现打包顺序是hello, weather, dinner。
所以,返回的闭包实际上相当于:

$closure = $dinner($weather($hello($meet))); // 记为make_closure行$closure('beauty');  // 记为run_closure

困惑的地方在于,为什么weather的执行顺序在hello前。常规的函数如A(B(C('hehe'))), 执行顺序应该是C,B,A。

因为中间件是一个闭包,而且返回一个闭包(满屏尽是闭包),意味着一个中件间要运行两次。外层闭包在打包的时候执行,也就是iterator行 或者 make_closure行,同时决定里层的执行顺序。里层闭包在调用时执行, run_prepare行或run_closure行。

表达式$hello($meet) 返回的是$hello 的里层闭包而不是句柄,因为里层未执行,所以hello beauty不会出现。也就是说,$weather 的形参$handler 对应的实参就是$hello的里层闭包。当程序运行到weather_return_handler行时,$hello 的里层闭包才真正执行,这时$weather 的逻辑已经执行完了。

打包程序的作用可以概括为执行当前中间件的外层闭包,得到里层闭包作为参数,再传给下一个中间件的外层闭包,直至迭代结束。

1 0
原创粉丝点击