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

2023-11-11

<?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 的 值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

laravel middleware 中间件原码分析 之array_reduce getSlice 的相关文章

  • Laravel S3 检索视频以流式传输

    我通过 Laravel 应用程序将视频存储到 Amazon S3 效果很好 但我无法 流式传输 它们 这是例如 URL https website com video 342 qt api token a5a18c9f f5f6 5d66
  • 如何从 Laravel 执行存储过程

    我需要在表单提交数据后执行存储过程 我让存储过程按照我想要的方式工作 并且我的表单正常工作 我只是不知道从 laravel 5 执行 sp 的语句 它应该是这样的 执行 my stored procedure 但我似乎在网上找不到类似的东西
  • 如何在 Laravel 5 中对合并集合进行分页?

    我正在创建一个包含两种类型的对象的流 BluePerson 和 RedPerson 为了创建流 我获取所有这两个对象 然后将它们合并到一个集合中 这样做之后 我需要对它们进行分页 但是分页似乎是针对雄辩的模型和数据库查询 而不是集合 我见过
  • Laravel 保存/更新多对多关系

    谁能帮助我如何保存多对多关系 我有任务 用户可以有很多任务 任务可以有很多用户 多对多 我想要实现的是更新表格管理员可以将多个用户分配给特定任务 这是通过 html 多选输入完成的 name taskParticipants 这里的问题是
  • Laravel 使用 Ajax 上传文件

    我正在使用 Laravel 框架 我有一种向数据库添加新项目的形式 在该形式中用户还可以拖放文件 然后 会显示一个进度条 直到完成为止 使用 Ajax 将文件上传到服务器 提交该表格后 我运行addItem在控制器中运行 我想要执行 检查
  • 使用 PHPUnit 和 Mockery 进行 Laravel 测试 - 设置控制器测试的依赖关系

    在终于通过了我愚蠢的简单测试后 我有一种感觉 我做得不对 我有一个 SessionsController 负责显示登录页面并让用户登录 我决定不使用外观 这样我就不必扩展 Laravel 的 TestCase 并在单元测试中承受性能影响 因
  • 向 Laravel 的 Mailer 添加新的传输驱动程序

    我需要向 Laravel 的邮件包添加一个新的传输驱动程序 以便我可以通过默认情况下不支持的外部服务 Mailjet 发送电子邮件 编写传输驱动程序不会成为问题 但我找不到一种方法来连接并添加新的驱动程序 以便我可以继续正常使用 Larav
  • Laravel 5.1 date_format 验证允许两种格式

    我对传入的 POST 请求使用以下日期验证 trep txn date gt date format Y m d H i s u 这只允许这种日期 即 2012 01 21 15 59 44 8 我还想允许没有时间的日期 例如2012 01
  • php laravel Blade 模板不渲染

    我正在尝试使用 Laravel 和 twitter bootstrap 设置一个基本页面 我安装了 Laravel 并获得了通用的 你在这里 或 w e 图像 这样看起来很闪亮 对于 twitter bootstrap 我在 public
  • 无法通过 Vue.js 从 Laravel 后端下载文件 (pdf)(Axios 帖子)

    我在 Vue 中有一个多步骤表单 一旦收集到所有信息 我就会将结果发布到 Laravel 控制器 这是网站的经过验证的区域 我正在使用护照 所以本质上我有一个 Vue SPA 它是在 Laravel 5 7 框架内构建的网站的管理区域 Vu
  • Laravel,控制器中的 Auth::user()

    Laravel 框架 为什么我无法在 laravel 项目的控制器中使用 Auth user 查看用户是否已登录 Session 是否未连接到控制器 HomeController php public function isauthoriz
  • PhpStorm背景错误

    PhpStorm更新后 Blade模板中 script标签突出显示 在设置中 一切正常 为什么要突出显示这一点 检查语言注入中是否有非 内置 行 禁用您不认识的项目
  • 如何从一行获取数据并移动到模态?拉拉维尔 5.4

    我有一个表 其中列出了数据库中的产品 其中包含 ID 名称 描述以及其他数据类型 我创建了一个按钮 该按钮将调用模态来显示有关产品的更多详细信息 但是模态始终显示表中第一个产品的详细信息 而不是与其相关的 ID 我的桌子 我的表代码 tab
  • 创建 Laravel 服务类

    我的正常运行时间 php
  • 如何在 Laravel 中将秒转换为天小时分钟[重复]

    这个问题在这里已经有答案了 我想将以秒为单位的时间间隔转换为天小时分钟 我已经尝试过了 value 90060 CarbonInterval seconds value gt forHumans 我得到了输出 90060 seconds 我
  • 我如何加入 Eloquent:关系?

    我的查询是这样的
  • Laravel 无法连接 Oracle

    我在用着耶吉拉 laravel oci8 https github com yajra laravel oci8用于 Oracle 与 Laravel 的连接 但我无法从客户端 PC 连接到 Oracle 服务器 showing this
  • https 重定向 laravel .htaccess 之后删除 /public

    我有一个 Laravel 页面部署在共享主机中 当我强制 http 请求重定向到 https 时 url 包含 public 我的根 htaccess 是 RewriteEngine on RewriteCond REQUEST URI p
  • Laravel 5.7:维护模式的自定义刀片模板,但不是 503.blade.php

    每次php artisan down开启后 Laravel 显示 503 页面 好的 我可以通过创建名为的新文件来自定义它503 blade php inside resources views errors 关键是 我在任何时候都不认为维
  • Laravel 4.2 Composer 安装错误:“无法扫描类”

    我想通过 Composer 在新的 Laravel 4 2 安装上安装一些软件包 但是 我遇到了例外 这是我的作曲家文件 name laravel laravel description The Laravel Framework keyw

随机推荐

  • msys2使用QT的mingw编译器编译ffmpeg

    使用的时候最好关闭杀毒软件 否则configure和make会很慢 window编译ffmpeg mingw 要在windows搭建一个模拟linux环境 下载安装MSYS2 64 网址 https www msys2 org 我这里安装在
  • linux中git安装步骤,linux配置安装 git 详细教程

    Git是目前流行的非常好用的版本控制工具 这里介绍两种安装方式 1 yum安装 2 从github上下载最新的源码编译后安装 一 环境介绍 系统 linux 镜像 CentOS 7 x86 64 DVD 1804 iso 二 源码安装 1
  • linux中命令du -sm,Linux中的Du命令

    du命令是 disk usage 的缩写 展示文件或目录使用的估计磁盘空间量 这对于查找占用大量磁盘空间的文件和目录很有用 如何使用du命令 du命令的常规语法如下 du OPTIONS FILE 如果给定的FILE是目录 du则将汇总该目
  • hibernate 根据实体类自动生成表

    常规的思路是 设计好数据库 建好表 借助MyEclipse 也可以是其他IDE 自动生成映射 或者自己写映射 早就听说hibernate中可以自动生成表 但是一直没有试验 今天首先介绍其中的一个属性hbm2ddl auto 这个就是这个方案
  • 与老范对谈:ChatGPT等AIGC技术对内容产业的影响和趋势判断

    昨日 我和老范线下面基 用一下午的时间深入探讨了AIGC对内容产业影响的话题 这次聊天收获满满 我迫不及待将这次讨论的内容整理成了文章 但在这之前 请让我先介绍一下老范 老范曾就职于盛大创新院 猎豹移动 是Tiktok的早期投资人 是一名互
  • 手里有几万块能做什么副业?一万块钱搞什么副业

    最近几年来 兼职 副业已经成为大家的刚需了 否则上班的收入已经满足不了开支了 我相信很多人手上都有1万元或者2万元左右甚至更多的闲钱 那么 有闲钱可以干什么 手上有一万元能投资做什么 1 做微商 微商可以说是近些年最热门的职业之一了 你既可
  • IDEA常用配置之代码自动格式化删除无用导入

    文章目录 IDEA常用配置之代码自动格式化删除无用导入 配置步骤 安装google java format 安装Save Actions 自动优化导包选项 检查行分隔符 缩进大小 IDEA常用配置之代码自动格式化删除无用导入 配置步骤 安装
  • Mac安装brew

    终极方法 不需要代理 百分百成功运行 bin zsh c curl fsSL https gitee com cunkai HomebrewCN raw master Homebrew sh 运行结果如下
  • AD 多边形 圆形 快速覆铜

    1 先确认你的板框 如下图 在Keep Out Layer 层 使用shift S键隐藏其他的层 2 全选板框 按T G M 输入法英文状态下 或手动选择 工具 多边形填充 多边形管理器 进入下图状态 选择图上标志的地方 选择板外形 如下图
  • 机器学习 day35(决策树)

    决策树 上图的数据集是一个特征值X采用分类值 即只取几个离散值 同时也是一个二元分类任务 即标签Y只有两个值 上图为之前数据集对应的决策树 最顶层的节点称为根节点 椭圆形节点称为决策节点 矩形节点称为叶子节点 决策树学习算法的工作是 在所有
  • Jetson Nano 40 pin 功能介绍

    40 根引脚主要分成GPIO General Purpose I O 通用功能与SFIO Special Function I O 特定功能 一 SFIO 18根 1 5V 直流电输入 输出 脚位 2 4 在排针脚塑料使用 红色 标识 2根
  • Java SE 16 record 类型说明与使用

    Java SE 16 record 类型说明与使用 作者 Grey 原文地址 博客园 Java SE 16 record 类型说明与使用 CSDN Java SE 16 record 类型说明与使用 说明 record 是 Java SE
  • Python3 爬取PAT个人乙级题所有答案代码

    Python3 爬取PAT个人乙级题所有答案 进入PAT乙级题题目页面 下面是链接 https pintia cn problem sets 994805260223102976 problems type 7 点开两个题目 观察两个链接有
  • 实验吧——认真一点!

    coding utf8 import requests import urllib 设置代理 用于调试过程中抓包分析 proxies http http localhost 9008 https http localhost 9008 he
  • 使用eclipse快速全局替换指定字符串

    1 按住 Ctrl H 调出全局搜索框 选择 File Search 文件搜索栏 2 输入需要搜索的字段和文件类型 点击下方的 Replace 按钮 如果搜索到对应的结果 则会弹出替换界面 此时输入需要替换的字段即可 具体操作如下图所示
  • Vue2 新手上路无处不在的特殊符号,让人傻傻分不清 “:”、“.”、“@”、“#” 、“{{}}“ 、“$“,‘$bus‘,‘$event‘

    背景 刚刚学vue没多久 经常分不清情况什么时候用什么符号 是指令 v bind 的缩写 是修饰符 是指令 v on 的缩写 它用于监听 DOM 事件 是v slot的缩写 插值语法 Vue 实例还暴露了一些有用的实例属性与方法 它们都有前
  • SG-Former:具有进化Token重新分配的自引导Transformer

    文章目录 摘要 1 简介 2 相关研究 3 方法 3 1 概述 3 2 自引导注意力 3 3 混合尺度注意力 3 4 Transformer块 3 5 Transformer架构变体 4 实验 4 1 ImageNet 1K的分类 4 2
  • TensorRT C++ 序列化serialize / 反序列化deserialize

    序列化Engine serialize the engine then close everything down const std string engine file tensorrt mnist trt nvinfer1 IHost
  • [数据结构复习]广义表

    1 形式 类似于 A B C D E F 2 广义表的存储 链表 每个节点的结构为 type 0表示附加头节点 1表示原子节点 2表示子表节点 data type 0时存放引用计数 1时存放data 2时存放指向子表表头的指针 link t
  • laravel middleware 中间件原码分析 之array_reduce getSlice