最近学习PHP,看到了一段代码,其中涉及到了匿名函数以及array_reduce,把代码敲出来用各种方法分析也没想出是怎么调用的,代码如下:
<?php
interface Middleware
{
public static function handle(Closure $next);
}
class VerifyCsrfToken implements Middleware
{
public static function handle(Closure $next)
{
echo "(5)验证Csrf-Token".'<br>';
$next();
}
}
class ShareErrorsFromSession implements Middleware
{
public static function handle(Closure $next)
{
echo "(4)如果session中有'errors'变量,则共享它".'<br>';
$next();
}
}
class StartSession implements Middleware
{
public static function handle(Closure $next)
{
echo "(3)开启session,获取数据".'<br>';
$next();
echo "(7)保存数据,关闭session".'<br>';
}
}
class AddQueuedCookiesToResponse implements Middleware
{
public static function handle(Closure $next)
{
$next();
echo "(8)添加下一次请求需要的cookie".'<br>';
}
}
class EncryptCookies implements Middleware
{
public static function handle(Closure $next)
{
echo "(2)对输入请求的cookie进行解密".'<br>';
$next();
echo "(9)对输出相应的cookie进行加密".'<br>';
}
}
class CheckForMaintenanceMode implements Middleware
{
public static function handle(Closure $next)
{
echo "(1)确定当前程序是否处于维护状态".'<br>';
$next();
}
}
function getSlice()
{
return function($stack, $pipe)
{
return function() use ($stack, $pipe)
{
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = [
"CheckForMaintenanceMode",
"EncryptCookies",
"AddQueuedCookiesToResponse",
"StartSession",
"ShareErrorsFromSession",
"VerifyCsrfToken"
];
$firstSlice = function() {
echo "(6)请求向路由器传递,返回响应.".'<br>';
};
$pipes = array_reverse($pipes);
$go = array_reduce($pipes, getSlice(),$firstSlice);
$go();
}
then();
?>
还望有大神能帮忙详解下$go = array_reduce($pipes, getSlice(),$firstSlice);和$go();这两段代码背后的每一步的调用执行流程,以及调用时的参数传递是哪些,如果能用流程图表示就更好啦,谢谢。
那么久了还没人回答.我来回答一下吧.
首先是这样的.我们看下面的代码来理解一下
上面的结果为50.那么它的过程是怎么样的呢?我们对代码进行改良
然后可以看到如下输出
第一个v1 = 5,v2 = 10;
第二个v1 = 15 (前一个返回的值) , v2 = 15; $a[1]的值;
第三个v1 = 30 (上一次的返回值) , v2 = 20; $a[2]的值;
最后输出50. 那么我们看第一个值为什么是5? 因为array_reduce接收的第3个参数就是表示当第一次迭代的时候传递的值。下面我们来自己实现一个array_reduce去深度的理解它 :)
这样是不是好多了呢?
下面是根据题主的问题进行补充
当arr 是上面的数组 以及回调的方法是上面的方法时.我们来看看发生了什么
首先
1.getSlice的返回值是function
当arr第一次循环的时候,根据我们上面所提到的array_reduce的原理看看发生了什么?
首先看这里
$go = array_reduce($pipes, getSlice(),$firstSlice);
第二个参数传的并不是callback 而是 直接写的 getSlice(); 那么这个函数将会直接执行并且将返回值传递给 array_reduce的第二个参数.
也就是直接返回
也就是和下面的写法是等价的。
只是因为前者的写法更加优雅 易于让ide查找;
弄清楚了这个我们接下来继续看。
当第一次迭代的时候 $stack 的值为$firstSlice
pipe 的值 为 VerifyCsrfToken.
那么这个函数被执行了.$firstSlice当作参数。
所以当调用$go();时
所有的pipe::handle方法会立即执行。
而每次都把$stack作为参数
所以执行顺序是倒过来了。因为到最后一次的时候 $next 才 === $firstSlice
再来回顾这段代码.为什么VerifyCsrfToken1先执行呢?
因为当foreach执行完毕的时候. $item = $pipes[count($pipes)-1];
也就是最后一个而 $v 永远为上一个return 的 值。