Die Beispiele in diesem Artikel beschreiben die Middleware-Implementierungsprinzipien von Laravel. Teilen Sie es als Referenz mit allen. Die Details lauten wie folgt:
#1 Was ist Middleware?
Bei einer Webanwendung können wir vor der tatsächlichen Verarbeitung einer Anfrage verschiedene Beurteilungen der Anfrage vornehmen, bevor sie an eine tiefere Ebene weitergeleitet werden kann. Und wenn wir if else wie dieses verwenden, wird es schwieriger, den Code zu warten, sobald immer mehr Bedingungen beurteilt werden müssen, und die Kopplung zwischen Systemen wird zunehmen, und Middleware kann dieses Problem lösen. Wir können diese Urteile in Middleware aufteilen, die Anfragen leicht filtern kann.
#2 Middleware in Laravel
In Laravel basiert die Implementierung der Middleware tatsächlich auf der Implementierung der IlluminatePipelinePipeline-Klasse. Schauen wir uns zunächst den Code an, der die Middleware auslöst. Es ist ganz einfach: Übergeben Sie die Anfrage nach der Bearbeitung einfach an einen Abschluss und leiten Sie sie dann weiter.
public function handle($request, Closure $next) { //do something for $request return $next($request); }
#3 Interne Implementierung von Middleware
Wie oben erwähnt, wird Middleware von Pipeline implementiert und ihr Aufruf erfolgt in IlluminateRoutingRouter In
return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); });
Sie können sehen, dass der Middleware-Ausführungsprozess drei Methoden aufruft. Werfen wir einen Blick auf die Codes dieser drei Methoden:
Sendemethode
public function send($passable){ $this->passable = $passable; return $this; }
Tatsächlich macht die Sendemethode nichts. Es legt nur das Objekt fest, das in der Middleware weitergeleitet werden muss. In diesem Fall ist es die HTTP-Anforderungsinstanz.
through-Methode
public function through($pipes){ $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; }
through-Methode ist ebenfalls sehr einfach, nämlich festzulegen, welche Middleware-Prozesse verarbeitet werden müssen.
then-Methode
Hier kommt der wirklich schwierige Teil. Der Code der then-Methode ist sehr prägnant, aber nicht leicht zu verstehen.
public function then(Closure $destination){ //then方法接受一个闭包作为参数,然后经过getInitialSlice包装,而getInitialSlice返回的其实也是一个闭包,如果还不知道什么是闭包先去看PHP文档 $firstSlice = $this->getInitialSlice($destination); //反转中间件数组,主要是利用了栈的特性,用处接下来再说 $pipes = array_reverse($this->pipes); //这个call_user_func先不要看,它其实就是执行了一个array_reduce返回的闭包 return call_user_func( //接下来用array_reduce来用回调函数处理数组,建议先去PHP文档读懂array_reduce的执行原理。其实arrary_reduce什么事情都没干,就是包装闭包然后移交给call_user_func来执行 array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); }
Auf diese Weise wird die gesamte Middleware nicht weitergegeben.
Da der zweite Parameter von aray_reduce eine Funktion erfordert, konzentrieren wir uns hier auf den Quellcode der getSlice()-Methode
protected function getSlice(){ return function ($stack, $pipe) { //这里$stack return function ($passable) use ($stack, $pipe) { if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } else { list($name, $parameters) = $this->parsePipeString($pipe); return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); } }; }; }
Schauen Sie, es kann sein, dass Ihnen schwindelig wird, der Verschluss kehrt zum Verschluss zurück. Zur Vereinfachung gibt getSlice() eine Funktion A zurück und Funktion A gibt Funktion B zurück. Warum zwei Funktionen zurückgeben? Weil wir $next($request) verwenden, um das Objekt während des Übertragungsprozesses zu übergeben, und $next($request) bedeutet, dass der Abschluss ausgeführt wird. Dieser Abschluss ist Funktion A und gibt dann Funktion B zurück, an die übergeben werden kann die nächste Middleware.
Lassen Sie uns den Code noch einmal vereinfachen:
//这里的$stack其实就是闭包,第一次遍历的时候会传入$firstSlice这个闭包,以后每次都会传入下面的那个function; 而$pipe就是每一个中间件 array_reduce($pipes, function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { }; }, $firstSlice);
Sehen Sie sich diesen Code noch einmal an:
//判断是否为闭包,这里就是判断中间件形式是不是闭包,是的话直接执行并且传入$passable[请求实例]和$stack[传递给下一个中间件的闭包],并且返回 if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); //不是闭包的时候就是形如这样Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode执行 } else { //解析,把名称返回,这个$parameters看了许久源码还是看不懂,应该是和参数相关,不过不影响我们的分析 list($name, $parameters) = $this->parsePipeString($pipe); //从容器中解析出中间件实例并且执行handle方法 return call_user_func_array([$this->container->make($name), $this->method], //$passable就是请求实例,而$stack就是传递的闭包 array_merge([$passable, $stack], $parameters)); }
Sehen Sie sich ein anderes Bild an:
Jede Iteration übergibt den vorherigen Abschluss und die Middleware, die aufgrund der Umkehrung ausgeführt werden muss Das Array wird basierend auf der First-In-Last-Out-Funktion des Stapels übertragen, sodass Middleware 3 zuerst gepackt wird und Middleware 1 sich auf der äußersten Ebene befindet. Denken Sie daran, dass array_reduce keinen Middleware-Code ausführt, sondern Middleware umschließt.
Nachdem Sie dies gesehen haben, sollten Sie verstehen, dass array_reduce schließlich func3 zurückgibt, dann ist call_user_func(func3,$this->passable) tatsächlich
return call_user_func($middleware[0]->handle, $this->passable, func2);
und das Handle in unserem Middleware-Code ist:
public function handle($request, Closure $next) { return $next($request); }
Dies entspricht der Rückgabe von func2($request). Die $request wird hier von der vorherigen Middleware verarbeitet. Der Prozess der Zhengguo-Middleware ist also abgeschlossen und es ist etwas verwirrend, ihn zu verstehen. Denken Sie daran, dass am Ende der äußerste Aufruf von call_user_func den Middleware-Code ausführt.
Ich hoffe, dass dieser Artikel für das PHP-Programmdesign aller hilfreich sein wird auf dem Laravel-Framework geholfen.
Ausführlichere Erläuterungen zu den Implementierungsprinzipien der Laravel-Middleware und verwandte Artikel finden Sie auf der chinesischen PHP-Website!