Description
ThinkPHP 6.0 RC5에서는 파이프라인 모드를 사용하여 미들웨어를 구현하기 시작했는데, 이는 이전 버전의 구현보다 더 간결하고 질서정연해졌습니다. 이 기사에서는 구현 세부 사항을 분석합니다.
먼저 항목 파일 public/index.php에서 시작합니다. $http = (new App())->http;
http 클래스의 인스턴스 가져오기 그리고 이를 실행 메소드라고 부릅니다: $response = $http->run(); 그런 다음 실행 메소드는 runWithRequest 메소드를 호출합니다:
protected function runWithRequest(Request $request) { . . . return $this->app->middleware->pipeline() ->send($request) ->then(function ($request) { return $this->dispatchToRoute($request); }); }
미들웨어 실행은 최종 return 문에 있습니다.
pipeline, 통해, 전송 방법
$this->app->middleware->pipeline() 的 pipeline 方法: public function pipeline(string $type = 'global') { return (new Pipeline()) // array_map将所有中间件转换成闭包,闭包的特点: // 1. 传入参数:$request,请求实例; $next,一个闭包 // 2. 返回一个Response实例 ->through(array_map(function ($middleware) { return function ($request, $next) use ($middleware) { list($call, $param) = $middleware; if (is_array($call) && is_string($call[0])) { $call = [$this->app->make($call[0]), $call[1]]; } // 该语句执行中间件类实例的handle方法,传入的参数是外部传进来的$request和$next // 还有一个$param是中间件接收的参数 $response = call_user_func($call, $request, $next, $param); if (!$response instanceof Response) { throw new LogicException('The middleware must return Response instance'); } return $response; }; // 将中间件排序 }, $this->sortMiddleware($this->queue[$type] ?? []))) ->whenException([$this, 'handleException']); }
방법 코드를 통해:
public function through($pipes) { $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; }
PHP의 array_map 메소드 서명:
array_map ( callable $callback , array $array1 [, array $... ] ) : array
function ($request, $next) { $response = handle($request, $next, $param); return $response; }
public function send($passable) { $this->passable = $passable; return $this; }
then, carry 메서드
send 메서드를 호출한 다음 then 메서드를 호출합니다.return $this->app->middleware->pipeline() ->send($request) ->then(function ($request) { return $this->dispatchToRoute($request); });
then 메소드 코드:
public function then(Closure $destination) { $pipeline = array_reduce( //用于迭代的数组(中间件闭包),这里将其倒序 array_reverse($this->pipes), // array_reduce需要的回调函数 $this->carry(), //这里是迭代的初始值 function ($passable) use ($destination) { try { return $destination($passable); } catch (Throwable | Exception $e) { return $this->handleException($passable, $e); } }); return $pipeline($this->passable); }
캐리 코드:
protected function carry() { // 1. $stack 上次迭代得到的值,如果是第一次迭代,其值是后面的「初始值 // 2. $pipe 本次迭代的值 return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { try { return $pipe($passable, $stack); } catch (Throwable | Exception $e) { return $this->handleException($passable, $e); } }; }; }
public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { return $pipe($passable, $stack); }; }, function ($passable) use ($destination) { return $destination($passable); }); return $pipeline($this->passable); }
(A)
function ($passable) use ($destination) { return $destination($passable); });
(B)
function ($passable) use ($stack, $pipe) { return $pipe($passable, $stack); };
(C)
function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($destination) { return $destination($passable); }) ); };
#🎜🎜 #
(D)// 伪代码
// 每一层的$pipe都代表一个中间件闭包
function ($passable) use ($stack, $pipe) {
return $pipe($passable, //倒数第二层中间件
function ($passable) use ($stack, $pipe) {
return $pipe($passable, //倒数第一层中间件
function ($passable) use ($destination) {
return $destination($passable); //包含控制器操作的闭包
})
);
};
);
};
클로저를 레이어별로 래핑한 후 양파 구조와 유사한 "슈퍼" 클로저 D를 얻습니다. 이 클로저의 구조는 위의 코드 주석에 표시된 대로입니다. 마지막으로 $request 객체를 이 클로저에 전달하고 실행합니다: $pipeline($this->passable); 그러면 양파 껍질을 벗기는 것과 유사한 프로세스가 시작됩니다. 다음으로 양파 껍질을 벗기는 방법을 살펴보겠습니다.
양파 껍질 벗기기 과정 분석array_map(...) 각 미들웨어 클래스를 이 구조와 유사한 클로저로 처리합니다. :
function ($request, $next) { $response = handle($request, $next, $param); return $response; }
손잡이는 미들웨어의 입구이며 그 구조적 특징은 다음과 같습니다.
public function handle($request, $next, $param) { // do sth ------ M1-1 / M2-1 $response = $next($request); // do sth ------ M1-2 / M2-2 return $response; }
위의 "양파"는 총 2개의 레이어만 있습니다. M1-1과 M1-2가 각각 첫 번째 미들웨어 처리 방법의 접두사 및 사후 값 작업 지점이라고 가정하면 계층 미들웨어가 닫힙니다. 두 번째 미들웨어인 M2-1과 M2-2도 마찬가지입니다. . 이제 프로그램이 $pipeline($this->passable)을 실행하고 확장하도록 합니다. 즉, 다음을 실행합니다:
// 伪代码 function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($destination) { return $destination($passable); }) ); }; ); }($this->passable)
이 때 프로그램은 다음에서 반환해야 합니다:
return $pipe($passable, function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($destination) { return $destination($passable); }) ); }; );
function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($destination) { return $destination($passable); }) ); }
function ($passable) use ($stack, $pipe) { return $pipe($passable, function ($passable) use ($destination) { return $destination($passable); }) ); }($request)
function ($passable) use ($destination) { return $destination($passable); })
function ($passable) use ($destination) { return $destination($passable); })($request)
最终,我们从 return $destination($passable) 中返回一个 Response 类的实例,也就是,第二层的 $response = $next($request) 语句成功得到了结果,接着执行下面的语句,也就是 M2-2 点位,最后第二层闭包返回结果,也就是第一层闭包的 $response = $next($request) 语句成功得到了结果,然后执行这一层闭包该语句后面的语句,即 M1-2 点位,该点位之后,第一层闭包也成功返回结果,于是,then 方法最终得到了返回结果。
整个过程过来,程序经过的点位顺序是这样的:M1-1→M2-1→控制器操作→M2-2→M1-2→返回结果。
总结
整个过程看起来虽然复杂,但不管中间件有多少层,只要理解了前后两层中间件的这种递推关系,洋葱是怎么一层层剥开又一层层返回的,来多少层都不在话下。
위 내용은 ThinkPHP6.0 파이프라인 모드 및 미들웨어 구현 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!