Larave 6.0 Middleware剖析
Rquest
封装并拷贝了PHP的$_SERVER,$_COOKIE,$_POST,$_GET这些跟request相关的东西.
PipeLine 机制
首先理解pipeline机制,所有的pipeline机制都有类似的机理:
object-->[ stop1 -- > stop2 --> stop3 ->final stop] --> result
traveler: 传到pipeline的被处理的对象
stops: 每个pipeline节点的处理对象
method: 每个pipline的处理方法
接口:
interface Pipeline
{
/**
* Set the traveler object being sent on the pipeline.
*/
public function send($traveler);
/**
* Set the stops of the pipeline.
*/
public function through($stops);
/**
* Set the method to call on the stops.
*/
public function via($method);
/**
* Run the pipeline with a final destination callback.
*/
public function then(Closure $destination);
}
then是真正的调用, 就是1个reduce
,PHP里是array_reduce
,reduce确实是实现流水的最好方法,么有之一.
//D:\Projects\PHP\laravel\plus\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
reduce数组的内容,即pipe可以是闭包,object, string:
then的每一步处理是:
1 pipe是闭包函数, 参数接受passable和当前处理的结果stack, 直接调用
- 调用该闭包,返回结果
2 pipe是string, 取name和parameters出来;
- name 可能已经注入过容器了,make出来再使用
3 pipe是object,不需要做什么
最后, 2 和 3 都调用pipe object里定义的handle方法 or 将pipe直接调用:(__invoke)
protected function carry()
{
//reduce的执行函数,
//array_reduce方法:
//<https://www.php.net/manual/zh/function.array-reduce.php>
//then处理的核心架构核心:reduce
return function ($stack, $pipe) {
//stack是上次迭代结果 ,是闭包,也就是下面这个return决定
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.
return $pipe($passable, $stack);
} elseif (! is_object($pipe)) {
[$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];
}
//stack 都交给给了handle做参数, 真正的执行stack的地方还是handle
$response = method_exists($pipe, $this->method)
? $pipe->{$this->method}(...$parameters)
: $pipe(...$parameters);
return $response instanceof Responsable
? $response->toResponse($this->getContainer()->make(Request::class))
: $response;
};
};
}
对应middleware里的handle:
//对应上面的passable, stack
public function handle($request, Closure $next) {
$repsonse = $next($request);
return $response;
}
搞清楚了上面的pipeline机制,理解laravel的Middleware顺利成章:
//D:\Projects\PHP\laravel\plus\vendor\laravel\framework\src\Illuminate\Foundation\Http
return (new Pipeline($this->app))
//设定 request作为处理对象
->send($request)
//设定 经过所有的middleware,也就是中间件,就是 pipeline里的元素
// 每个middleware都会调用1次handle
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
//最后的开始执行, 制定完毕交给router
->then($this->dispatchToRouter());
最后到router处理里去了:
protected function dispatchToRouter()
{
return function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
};
}