laravel middleware 之 array_reduce 详解

array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值。
www.php.net/manual/zh/function.arr...

<?php
$array = [
  'middleware1', 
  'middleware2', 
  'middleware3',
];

$callback  = function ($strack, $item) {
  return $strack . '-' .$item;
};

$initial = 'initial';

$res = array_reduce($array, $callback, $initial);

print_r($res); // "initial-mdware1-mdware2-mdware3"

第一次迭代
array_reduce 详解

第二次迭代
array_reduce 详解

第三次迭代
array_reduce 详解

数组迭代完毕返回最后的栈结果 "initial-mdware1-mdware2-mdware3",如果迭代的数组为空,则为初始栈 "initial",如果 array_reduce 第三个参数不填写,则初始栈为 null

此时仅仅是字符串相加,在 laravel 中的中间件自然都是功能体,功能体的意思是要么是闭包、要么是类的方法,我们将上边例子中的字符串全部换成功能体 :闭包。

<?php
$array = [
  function($next) {
    echo "mdware1";
    $next();
  },
  function ($next) {
    echo "mdware2";
    $next();
  },
  function ($next) {
    echo "mdware3";
    $next();
  },
];

$callback  = function ($strack, $item) {
  return $item($strack);
};

$initial = function() {
  echo 'initial';
};

$res = array_reduce($array, $callback, $initial);

print_r($res);

此时我们简单的认为中间件这样编写

function($next) {
    echo "mdware1";
    $next();
}

即可以把上一次的栈包含到自己的功能体中,并且晚于 echo "mdware1" 调用,便实现了中间件的效果。但是出现一个问题,第一次迭代时 callback 方法中的 return $item($strack) 返回的栈是这样

function($next) {
    echo "mdware1";
    $next();
}(
    function() {
        echo 'initial';
    }
)

结果是直接调用了,输出的栈是字符串 "mdware1initial",代表已经输出响应了,无法下一次迭代。
所以每次迭代返回的栈还应该是一个功能体,不能提前调用,因此改造 callback 如下:

$callback  = function ($strack, $item) {
  return function() use ($strack, $item) {
    return $item($strack);
  };
};

思考点:为什么是 use 而不是 function($strack, $item)

这样则返回的栈是一个闭包,其代码并未调用。但值得注意的是 $strack, $item 保存了当前的状态,这正是利用了闭包的特性。

array_reduce 详解

这个栈只需调用

function() use ($strack, $item) {
    return $item($strack);
}()

就可以输出结果 "mdware1initial"
但迭代还未结束,当迭代完成后的最后一个栈,然后我们 栈() 调用就可以了。

array_reduce 详解

整个 array_reduce 调用完毕后返回闭包

function() use ($strack, $item) {
    return $item($strack);
}

此时闭包保存的变量状态为: $strack 为第二个栈,$itemmdware3 ⌈不理解的话看上图,因最后一次迭代是 mdware3,上一次迭代的栈是其参数⌋。$item($strack) 即调用时代码如下:

function ($next) {
    echo "mdware3";
    $next();
}(2),

栈2 仍是一个闭包,$next()栈2()

function() use ($strack, $item) {
    return $item($strack);
}()

但其闭包保存的变量状态为: $strack 为第一个栈,$itemmdware2,即调用时代码如下:

function ($next) {
    echo "mdware2";
    $next();
}(1)

栈1 仍是一个闭包,$next()栈1()

function() use ($strack, $item) {
    return $item($strack);
}()

但其闭包保存的变量状态为: $strack 为初始栈,$itemmdware1,即调用时代码如下:

function($next) {
    echo "mdware1";
    $next();
}(function(){
  echo "initial";
})

最后将完整代码贴下

<?php
$array = [
  function($next) {
    echo "mdware1.." . PHP_EOL;
    $next();
  },
  function ($next) {
    echo "mdware2" . PHP_EOL;
    $next();
  },
  function ($next) {
    echo "mdware3" . PHP_EOL;
    $next();
  },
];

$callback  = function ($strack, $item) {
  $cb = function() use ($strack, $item) {
    return $item($strack);
  };
  return $cb;
};

$initial = function() {
  echo 'initial' . PHP_EOL;
};

$res = array_reduce($array, $callback, $initial);

print_r( $res() );
PS D:\MyCode\study\php\code> php 1.php
mdware3
mdware2
mdware1..
initial

可能此时有人注意了,mdware 执行是反的,这是因为最先迭代的是最内层的,因此我们把 $array array_reverse() 反转下就可以了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
welcome come back
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
79
粉丝
20
喜欢
129
收藏
306
排名:358
访问:2.5 万
私信
所有博文
社区赞助商