欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Laravel中間件實現(xiàn)原理詳解

 更新時間:2016年10月09日 11:39:21   作者:夏天的風(fēng)  
這篇文章主要介紹了Laravel中間件實現(xiàn)原理,較為詳細的分析了Laravel中間件的概念、原理及相關(guān)方法與使用技巧,需要的朋友可以參考下

本文實例講述了Laravel的中間件實現(xiàn)原理。分享給大家供大家參考,具體如下:

#1 什么是中間件?

對于一個Web應(yīng)用來說,在一個請求真正處理前,我們可能會對請求做各種各樣的判斷,然后才可以讓它繼續(xù)傳遞到更深層次中。而如果我們用if else這樣子來,一旦需要判斷的條件越來越來,會使得代碼更加難以維護,系統(tǒng)間的耦合會增加,而中間件就可以解決這個問題。我們可以把這些判斷獨立出來做成中間件,可以很方便的過濾請求。

#2 Laravel中的中間件

在Laravel中,中間件的實現(xiàn)其實是依賴于Illuminate\Pipeline\Pipeline這個類實現(xiàn)的,我們先來看看觸發(fā)中間件的代碼。很簡單,就是處理后把請求轉(zhuǎn)交給一個閉包就可以繼續(xù)傳遞了。

public function handle($request, Closure $next) {
  //do something for $request
  return $next($request);
}

#3 中間件內(nèi)部實現(xiàn)

上面說道,中間件是靠Pipeline來實現(xiàn)的,它的調(diào)用在Illuminate\Routing\Router中

return (new Pipeline($this->container))
            ->send($request)
            ->through($middleware)
            ->then(function ($request) use ($route) {
              return $this->prepareResponse(
                $request,
                $route->run($request)
              );
            });

可以看到,中間件執(zhí)行過程調(diào)用了三個方法。再來看看這三個方法的代碼:

send方法

public function send($passable){
  $this->passable = $passable;
  return $this;
}

其實send方法沒做什么事情,就是設(shè)置了需要在中間件中流水處理的對象,在這里就是HTTP請求實例。

through方法

public function through($pipes){
  $this->pipes = is_array($pipes) ? $pipes : func_get_args();
  return $this;
}

through方法也很簡單,就是設(shè)置一下需要經(jīng)過哪些中間件處理。

then方法

真正難懂的來了,then方法代碼很簡潔,但是要理解可不容易。

public function then(Closure $destination){
  //then方法接受一個閉包作為參數(shù),然后經(jīng)過getInitialSlice包裝,而getInitialSlice返回的其實也是一個閉包,如果還不知道什么是閉包先去看PHP文檔
  $firstSlice = $this->getInitialSlice($destination);
  //反轉(zhuǎn)中間件數(shù)組,主要是利用了棧的特性,用處接下來再說
  $pipes = array_reverse($this->pipes);
  //這個call_user_func先不要看,它其實就是執(zhí)行了一個array_reduce返回的閉包
  return call_user_func(  
    //接下來用array_reduce來用回調(diào)函數(shù)處理數(shù)組,建議先去PHP文檔讀懂a(chǎn)rray_reduce的執(zhí)行原理。其實arrary_reduce什么事情都沒干,就是包裝閉包然后移交給call_user_func來執(zhí)行
    array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
  );
}

然后就沒有然后了,這樣就過完了所有中間件,是不是很優(yōu)雅?

由于aray_reduce的第二個參數(shù)需要一個函數(shù),我們這里重點看看getSlice()方法的源碼

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));
        }
      };
    };
}

看到可能會很頭暈,閉包返回閉包的。簡化一下就是getSlice()返回一個函數(shù)A,而函數(shù)A又返回了函數(shù)B。為什么要返回兩個函數(shù)呢?因為我們中間在傳遞過程中是用$next($request)來傳遞對象的,而$next($request)這樣的寫法就表示是執(zhí)行了這個閉包,這個閉包就是函數(shù)A,然后返回函數(shù)B,可以給下一個中間件繼續(xù)傳遞。

再來簡化一下代碼就是:

//這里的$stack其實就是閉包,第一次遍歷的時候會傳入$firstSlice這個閉包,以后每次都會傳入下面的那個function; 而$pipe就是每一個中間件
array_reduce($pipes, function ($stack, $pipe) {  
  return function ($passable) use ($stack, $pipe) {
  };
}, $firstSlice);

再來看這一段代碼:

//判斷是否為閉包,這里就是判斷中間件形式是不是閉包,是的話直接執(zhí)行并且傳入$passable[請求實例]和$stack[傳遞給下一個中間件的閉包],并且返回
if ($pipe instanceof Closure) {  
  return call_user_func($pipe, $passable, $stack);
//不是閉包的時候就是形如這樣Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode執(zhí)行
} else {  
  //解析,把名稱返回,這個$parameters看了許久源碼還是看不懂,應(yīng)該是和參數(shù)相關(guān),不過不影響我們的分析
  list($name, $parameters) = $this->parsePipeString($pipe); 
  //從容器中解析出中間件實例并且執(zhí)行handle方法
  return call_user_func_array([$this->container->make($name), $this->method], 
  //$passable就是請求實例,而$stack就是傳遞的閉包
  array_merge([$passable, $stack], $parameters));  
}

再看一張圖片:

每一次迭代傳入上一次的閉包和需要執(zhí)行的中間件,由于反轉(zhuǎn)了數(shù)組,基于棧先進后出的特性,所以中間件3第一個被包裝,中間件1就在最外層了。要記得,arrary_reduce他不執(zhí)行中間件代碼,而是包裝中間件。

看到這里應(yīng)該明白了,array_reduce最后會返回func3,那么call_user_func(func3,$this->passable)實際就是

復(fù)制代碼 代碼如下:
return call_user_func($middleware[0]->handle, $this->passable, func2);

而我們的中間件中的handle代碼是:

public function handle($request, Closure $next) {
  return $next($request);
}

這里就相當(dāng)于return func2($request),這里的$request就是經(jīng)過上一個中間件處理過的。所以正果中間件的過程就完了,理解起來會有點繞,只要記得最后是由最外面的call_user_func來執(zhí)行中間件代碼的

更多關(guān)于Laravel相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Laravel框架入門與進階教程》、《php優(yōu)秀開發(fā)框架總結(jié)》、《smarty模板入門基礎(chǔ)教程》、《php日期與時間用法總結(jié)》、《php面向?qū)ο蟪绦蛟O(shè)計入門教程》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總

希望本文所述對大家基于Laravel框架的PHP程序設(shè)計有所幫助。

相關(guān)文章

最新評論