本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

laravel中间件是个非常方便的东西,能将一些逻辑实现解耦,并且在laravel中,
中间件的编写也是非常的方便。谁用谁知道。

1.装饰器模式

laravel中的中间件使用的就是装饰器模式,什么是[装饰器模式][1],先去了解一下吧,这里大概说一下,就是这个模式主要的就是用于解决 当一个类需要动态扩展功能的时候,使用继承的方式会让子类膨胀,并且这个扩展的功能是个公用功能的情况下,不利于功能的复用以及代码的解耦。

在laravel,使用对于使用这种模式的功能,称为请求处理管道,也就是pipeline

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

//公共接口

interface middleware {

        public static function handle(Closure $next);

    }

//装饰器1

class MiddleStepOne implements middleware{

        public static function handle(Closure $next) {

            echo "前期处理的第一步"."<br>";

            $next();

            echo "后期处理的第一步"."<br>";

        }

    }

//装饰器2

class MiddleStepTwo implements middleware{

    public static function handle(Closure $next) {

        echo "前期处理的第二步"."<br>";

        $next();

        echo "后期处理的第二步"."<br>";

    }

}

function goFunc() {

    return function ($step,$className) {

      return function () use ($step,$className) {

          return $className::handle($step);

      };

    };

}

$pip = array(

    MiddleStepOne::class,

    MiddleStepTwo::class,

);

$pip = array_reverse($pip);  //反转数组,以求达到要求的顺序运行

$first = function (){

    echo "前期处理完毕"."<br>";

};  //实际要处理的函数

$a = array_reduce($pip,goFunc(),$first); //遍历pip数组,并将first作为第一个参数传递进去

$a(); //执行

输出:

这个就是一个简单的基于装饰器模式的管道。他的本质其实就是基于闭包和递归。

通过分析这个程序,对于最终生成的$a变量,它的值大概是这样的 MiddleStepOne.handle(MiddleStepTwo.handle(first)),当执行的时候因为在handle中有个next()函数的存在,所以这是一个递归的调用。对于laravel的中间件,他的实现原理也是和这个一样的。

链接:https://pan.baidu.com/s/1v5gm7n0L7TGyejCmQrMh2g 提取码:x2p5

免费分享,但是X度限制严重,如若链接失效点击链接或搜索加群 群号518475424

2.laravel中的中间件和请求处理管道

在laravel中,我们我们可以通过设置中间件来在请求执行之前做一些预先的处理。

从请求入口 public/index.php开始

重要的是这段代码:即 处理请求,返回请求的响应

1

2

3

$response = $kernel->handle(

$request = Illuminate\Http\Request::capture() //创建一个请求实例

);

接着我们进入kernel中看他的具体实现 IlluminateFoundationHttpKernel.php中


关于dispatchToRouter()函数请大家自己去看,这里就不多说了。

接下来就是激动人心的PipeLine类了,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

<?php

namespace Illuminate\Pipeline;

use Closure;

use RuntimeException;

use Illuminate\Contracts\Container\Container;

use Illuminate\Contracts\Pipeline\Pipeline as PipelineContract;

class Pipeline implements PipelineContract

{

    /**

     * The container implementation.

     *

     * @var \Illuminate\Contracts\Container\Container

     */

    protected $container;

    /**

     * The object being passed through the pipeline.

     *

     * @var mixed

     */

    protected $passable;

    /**

     * The array of class pipes.

     *

     * @var array

     */

    protected $pipes = [];

    /**

     * The method to call on each pipe.

     *

     * @var string

     */

    protected $method = 'handle';

    /**

     * Create a new class instance.

     *

     * @param  \Illuminate\Contracts\Container\Container|null  $container

     * @return void

     */

    public function __construct(Container $container = null)

    {

        $this->container = $container;

    }

    /**

     * Set the object being sent through the pipeline.

     *

     * @param  mixed  $passable

     * @return $this

     */

    public function send($passable)

    {

        $this->passable = $passable;

        return $this;

    }

    /**

     * Set the array of pipes.

     *

     * @param  array|mixed  $pipes

     * @return $this

     */

    public function through($pipes)

    {

        $this->pipes = is_array($pipes) ? $pipes : func_get_args();

        return $this;

    }

    /**

     * Set the method to call on the pipes.

     *

     * @param  string  $method

     * @return $this

     */

    public function via($method)

    {

        $this->method = $method;

        return $this;

    }

    /**

     * Run the pipeline with a final destination callback.

     *

     * @param  \Closure  $destination

     * @return mixed

     */

    public function then(Closure $destination)

    {

        $pipeline = array_reduce(

            array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)

        );

        return $pipeline($this->passable);

    }

    /**

     * Get the final piece of the Closure onion.

     *

     * @param  \Closure  $destination

     * @return \Closure

     */

    protected function prepareDestination(Closure $destination)

    {

        return function ($passable) use ($destination) {

            return $destination($passable);

        };

    }

    /**

     * Get a Closure that represents a slice of the application onion.

     *

     * @return \Closure

     */

    protected function carry()

    {

        return function ($stack, $pipe) {

            return function ($passable) use ($stack, $pipe) {

                if (is_callable($pipe)) {

                    // If the pipe is an instance of a Closure, we will just call it directly but

                    // otherwise we'll resolve the pipes out of the container and call it with

                    // the appropriate method and arguments, returning the results back out.

                    //如果pip也就中间件函数是一个闭包可调用函数,就直接返回这个闭包函数就行了

                    //这里我还没有找到对应的使用场景,后续补充

                    return $pipe($passable, $stack);

                } elseif (! is_object($pipe)) {

                    list($name, $parameters) = $this->parsePipeString($pipe);

                    // If the pipe is a string we will parse the string and resolve the class out

                    // of the dependency injection container. We can then build a callable and

                    // execute the pipe function giving in the parameters that are required.

                    $pipe = $this->getContainer()->make($name);

                    $parameters = array_merge([$passable, $stack], $parameters);

                } else {

                    // If the pipe is already an object we'll just make a callable and pass it to

                    // the pipe as-is. There is no need to do any extra parsing and formatting

                    // since the object we're given was already a fully instantiated object.

                    $parameters = [$passable, $stack];

                }

                return method_exists($pipe, $this->method)

                                ? $pipe->{$this->method}(...$parameters)

                                : $pipe(...$parameters);

            };

        };

    }

    /**

     * Parse full pipe string to get name and parameters.

     *

     * @param  string $pipe

     * @return array

     */

    protected function parsePipeString($pipe)

    {

        list($name, $parameters) = array_pad(explode(':', $pipe, 2), 2, []);

        if (is_string($parameters)) {

            $parameters = explode(',', $parameters);

        }

        return [$name, $parameters];

    }

    /**

     * Get the container instance.

     *

     * @return \Illuminate\Contracts\Container\Container

     * @throws \RuntimeException

     */

    protected function getContainer()

    {

        if (! $this->container) {

            throw new RuntimeException('A container instance has not been passed to the Pipeline.');

        }

        return $this->container;

    }

}

总的来说pipeLine类的实现和我之前写的修饰器是差不多,这里主要麻烦的地方就在于就在于

protected function carry()函数内部,对于当pip是闭包,字符串,还有对象的处理。

之前觉得laravel的中间件是个很神秘的东西,但是看了之后才觉得也就那样,很精巧,在实际开发中这种模式也是很有帮助的,例如我们目前用的一个gateway项目,因为没有使用任何框架,所以将判断条件剥离,写入到中间件中, 这样实现了一定程度上的模块化编程。

laravel框架的中间件middleware的详解的更多相关文章

  1. Laravel框架中的make方法详解

    为什么网上已经有这么多的介绍Laravel的执行流程了,Laravel的容器详解了,Laravel的特性了,Laravel的启动过程了之类的文章,我还要来再分享呢? 因为,每个人的思维方式和方向是不一 ...

  2. [转帖]ASP.NET Core 中间件(Middleware)详解

    ASP.NET Core 中间件(Middleware)详解   本文为官方文档译文,官方文档现已非机器翻译 https://docs.microsoft.com/zh-cn/aspnet/core/ ...

  3. Django框架 之 ORM查询操作详解

    Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...

  4. ORM框架对比以及Mybatis配置文件详解

    ORM框架对比以及Mybatis配置文件详解 0.数据库操作框架的历程 (1) JDBC ​ JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句 ...

  5. 第十九节:Scrapy爬虫框架之Middleware文件详解

    # -*- coding: utf-8 -*- # 在这里定义蜘蛛中间件的模型# Define here the models for your spider middleware## See doc ...

  6. Django 框架篇(四) : 视图(view)详解 以及 路由系统(url)

    |--Django的View(视图) |-- CBV和FBV: |-- 给视图增加装饰器: |-- request对象: |-- response对象: |-- Django的路由系统(url): | ...

  7. Hadoop框架:NameNode工作机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.存储机制 1.基础描述 NameNode运行时元数据需要存放在内存中,同时在磁盘中备份元数据的fsImage,当元数据有更新或者添加元数据 ...

  8. Hadoop框架:DataNode工作机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.工作机制 1.基础描述 DataNode上数据块以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是数据块元数据包括长度.校验.时 ...

  9. Django框架之中间件MiddleWare

    Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健 ...

随机推荐

  1. C#进阶之路(八)集合的应用

    集合是我们编程时候常用的类库,本文主要讨论具体每个类型的区别,每个集合对应的时间复杂度.先上一个时间复杂度图: C#集体类型( Collections in C#) 集合是.NET FCL(Frame ...

  2. C typedef、#define

    参考链接:https://www.runoob.com/cprogramming/c-typedef.html 作用 typedef是用来为数据类型(可以是各种数据类型,包括自己定义的数据类型如结构体 ...

  3. Hystrix核心熔断器

    在深入研究熔断器之前,我们需要先看一下Hystrix的几个重要的默认配置,这几个配置在HystrixCommandProperties 中 //时间窗(ms) static final Integer ...

  4. CSS 选择器大全

    在CSS中,选择器是用于选择要设置样式的元素的模式. 选择器 例子 描述 .class .intro 选择class=“intro”的所有元素 #id #firstname 选择id=“firstna ...

  5. html跳转,获取get提交参数

    html跳转到html页面,url后面携带参数,可以通过脚本获取到url?test=value地址后的参数. 1.more.html 携带参数跳转到list.html,get提交参数 2.list.h ...

  6. maven 学习---使用Maven清理项目

    在基于Maven的项目中,很多缓存输出在“target”文件夹中.如果想建立项目部署,必须确保清理所有缓存的输出,从面能够随时获得最新的部署. 要清理项目缓存的输出,发出以下命令: mvn clean ...

  7. 用SignApk.jar对APK进行签名

    对apk签名需要使用SignApk.jar和签名文件.可以使用Android源码获取,若没有源码,可以在这下载:SignApk.jar.(包含了SignApk.jar和签名文件和批处理文件) 1 Si ...

  8. Centos7部署分布式文件存储(Fastdfs)

    目录 FastDFS介绍 楼主目标:前可H5撩妹,后可Linux搞运维 环境:Centos7 软件: 软件链接: 安装前所有准备,上传软件到Centos7上的/opt的目录下 安装依赖软件和类库(安装 ...

  9. pyhive client连接hive报错处理:Could not start SASL

    本来一切就绪,镜像里已安装如下主要的pip包. pyhive configparser pandas hdfs thrift sqlparse sasl thrift-sasl 但,使用pyhive ...

  10. Ubuntu下使用linuxdeployqt打包Qt程序

    写了点Qt界面程序,然而发现很难移植到其他没有安装Qt环境的电脑上运行.查资料了解到,在windows上有windeployqt程序,linux上有linuxdeployqt可以帮助我们快速打包. 1 ...