laravel 框架 源码解读 03 Pipeline.php 管道类

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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<?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()
{
array_reduce() 函数向用户自定义函数发送数组中的值,并返回一个字符串。

注释:如果数组是空的且未传递 initial 参数,该函数返回 NULL

调用返回闭包 调用参数 第一个参数为 管道类 第二个参数为闭包
return function ($stack, $pipe) {
调用返回闭包 调用参数 为传入的变量 用了管道类 和 闭包
return function ($passable) use ($stack, $pipe) {
if ($pipe instanceof Closure) {
如果参数为闭包就直接调用闭包
第一次为初始化的闭包
// 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.
return $pipe($passable, $stack);
} elseif (! is_object($pipe)) {
如果参数不是对象 就解析 分成两个变量
8 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 $pipe->{$this->method}(...$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;
}
}
App\Http\Kernel;
有以下中间件
protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,

];

 public function handle($request, Closure $next)
{
    if ($this->app->isDownForMaintenance()) {
        $data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true);

        throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']);
    }

    return $next($request);
}
    中间价执行函数  传入经过管道的变量 和一个执行闭包