laravel middleware 中间件原码分析 之array_reduce getSlice

<?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();
?>
<?php
function myfunction($v1,$v2)
{
return $v1+$v2;
}
$a=array(10,15,20);
print_r(array_reduce($a,"myfunction",5)); //50
?>
 

上面的结果为50.那么它的过程是怎么样的呢?我们对代码进行改良

function myfunction($v1, $v2)
{
    var_dump($v1, $v2);
    return $v1 + $v2;
}
 
$a = array(10, 15, 20);
print_r(array_reduce($a, "myfunction", 5)); //50
echo "\n";

然后可以看到如下输出

int(5)
int(10)
int(15)
int(15)
int(30)
int(20)
50

第一个v1 = 5,v2 = 10;
第二个v1 = 15 (前一个返回的值) , v2 = 15; $a[1]的值;
第三个v1 = 30 (上一次的返回值) , v2 = 20; $a[2]的值;
最后输出50. 那么我们看第一个值为什么是5? 因为array_reduce接收的第3个参数就是表示当第一次迭代的时候传递的值。下面我们来自己实现一个array_reduce去深度的理解它 :)

function myfunction($v1, $v2)
{
    var_dump($v1, $v2);
    return $v1 + $v2;
}
 
$a = array(10, 15, 20);
print_r(my_array_reduce($a, "myfunction", 5)); //50
echo "\n";
 
 
/**
 * array_reduce
 * @param array $arr
 * @param callable $fn
 * @param null $initial
 * @return mixed
 */
function my_array_reduce(array $arr, callable $fn, $initial = null)
{
    $v = $initial;
    foreach ($arr as $item) {
        $v = $fn($v, $item);
    }
    return $v;
}

这样是不是好多了呢?

下面是根据题主的问题进行补充

$arr = [
    'VerifyCsrfToken'
];
 
function getSlice()
{
    return function($stack, $pipe)
    {
        return function() use ($stack, $pipe)
        {
            return $pipe::handle($stack);
        };
    };
}
 
$firstSlice = function() {
        echo "(6)请求向路由器传递,返回响应.".'<br>';
};
 
$go = array_reduce($pipes, getSlice(),$firstSlice);
$go();

当arr 是上面的数组 以及回调的方法是上面的方法时.我们来看看发生了什么
首先
1.getSlice的返回值是function

当arr第一次循环的时候,根据我们上面所提到的array_reduce的原理看看发生了什么?

$arr = [
    'VerifyCsrfToken'
];
 
function getSlice()
{
    return function($stack, $pipe)
    {
        return function() use ($stack, $pipe)
        {
            return $pipe::handle($stack);
        };
    };
}

首先看这里
$go = array_reduce($pipes, getSlice(),$firstSlice);
第二个参数传的并不是callback 而是 直接写的 getSlice(); 那么这个函数将会直接执行并且将返回值传递给 array_reduce的第二个参数.
也就是直接返回

function ($stack, $pipe) {
        return function () use ($stack, $pipe) {
            return $pipe::handle($stack);
        };
    };

也就是和下面的写法是等价的。

function getSlice($stack, $pipe)
{
    return function () use ($stack, $pipe) {
        return $pipe::handle($stack);
    };
}
 
$firstSlice = function () {
    echo "(6)请求向路由器传递,返回响应\n";
};
 
$go = my_array_reduce($pipes, "getSlice", $firstSlice);
$go();
  1. 只是因为前者的写法更加优雅 易于让ide查找;

弄清楚了这个我们接下来继续看。

return function () use ($stack, $pipe) {
     return $pipe::handle($stack);
};

当第一次迭代的时候 $stack 的值为$firstSlice
pipe 的值 为 VerifyCsrfToken.
那么这个函数被执行了.$firstSlice当作参数。
所以当调用$go();时
所有的pipe::handle方法会立即执行。
而每次都把$stack作为参数
所以执行顺序是倒过来了。因为到最后一次的时候 $next 才 === $firstSlice

 
$pipes = [
    "VerifyCsrfToken",
    "VerifyCsrfToken1"
];
 
/**
 * array_reduce
 * @param array $arr
 * @param callable $fn
 * @param null $initial
 * @return mixed
 */
function my_array_reduce($arr, callable $fn, $initial = null)
{
    $v = $initial;
    foreach ($arr as $item) {
        $v = $fn($v, $item);
    }
    return $v;
}

再来回顾这段代码.为什么VerifyCsrfToken1先执行呢?
因为当foreach执行完毕的时候. $item = $pipes[count($pipes)-1];
也就是最后一个而 $v 永远为上一个return 的 值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值