ホームページ > バックエンド開発 > PHPチュートリアル > Laravel のパイプラインを理解する

Laravel のパイプラインを理解する

WBOY
リリース: 2016-06-23 13:19:34
オリジナル
1402 人が閲覧しました

laravelの起動プロセス中に何度も登場するパイプラインは、laravelの起動プロセスやライフサイクルを理解する上で重要なポイントの一つです。パイプラインについての説明はインターネット上にほとんどないので、自分で書いてみます。
まず、コールスタック、つまり、リクエストの開始からレスポンスが返されるまでのlaravelの動作を見てみましょう。
次のようにルーティングを設定します

Route::get('/', function() {    return debug_backtrace();});
ログイン後にコピー

次に、laravel に付属する Web サーバーを起動します

php artisan serve
ログイン後にコピー


laravel に付属するサーバーを起動します


次に、localhost:8000/
にアクセスします。印刷されたコールスタックが表示されます。は非常に長いです... …


コールスタックを出力します


左下隅にあるように、リクエストの最初から最後まで、何も行われていないにもかかわらず、39 個のクラスがロードされたままです。 .. 優れたパフォーマンスを追求する学生は、慎重に検討する必要があります…
私たちが注目するのはパイプラインです。上記の手順に従うと、頻繁に呼び出されるパイプラインがあることがわかります。
それでは何に使われるのでしょうか?
簡単に言うと、Laravelでミドルウェアを実装することです。ミドルウェア コードについてよく考えてください

public function handle($request, Closure $next) {    //do something for $request    return $next($request);}
ログイン後にコピー

最終リクエストを取得する前に、リクエストはミドルウェア処理の層を通過します。これはどのように実装されますか?答えはパイプラインです
まずはパイプラインのマクロ体験と使い方、そして詳しく解説していきます


ソースコードでのパイプラインの使い方


ご覧のとおり、3つありますmain メソッドとパイプラインのすべてのメソッドが使用可能に公開されています。理解しやすいこと。次に、パイプラインがミドルウェアで使用されていると仮定し、送信オブジェクトは $request であると考えてください。実際、これは、ここで送信されるように設定されているものです。 . オブジェクトは後で渡され、A が処理された後、処理のために B に送信され、次に処理のために C に送信されます。 png

  • 名前が示すように、上記の send によって設定されたオブジェクトを処理するためにどのミドルウェアが使用されるか
  • /**  * Set the object being sent through the pipeline. *  * @param  mixed  $passable  * @return $this */public function send($passable) {        $this->passable = $passable;        return $this;}
    ログイン後にコピー
  • を介して呼び出す場合のパイプラインの使用方法の上記のスクリーンショット マクロの説明からわかるように。スルーで渡されるパラメーターを見てください。ミドルウェアを必要としない現在のリクエストを設定する場合は、空の配列を渡します。それ以外の場合は、事前定義されたミドルウェア配列を渡します。
  • パイプラインのコードは次のとおりです。
(new Pipeline($this))    ->send($request)    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)    ->then($this->dispatchToRouter());
ログイン後にコピー

これは非常に簡単に思えます。配列または複数の文字列を渡すと、配列に結合されます。それは問題ではありません。ミドルウェアの名前を指定するだけです

その後

次のステップはコアです。コードのあいまいな部分。

次に、すべての準備ができたら処理を開始するコマンドを発行する方法です。

以前は send と through が設定されており、他には何も行われていないことがわかります。つまり、渡されるオブジェクトと渡される必要があるミドルウェアが設定されたら、当然処理が開始されます。

まずコードを見てみましょう

/**   * Set the array of pipes.   *   * @param  dynamic|array  $pipes   * @return $this */public function through($pipes){        $this->pipes = is_array($pipes) ? $pipes : func_get_args();        return $this;}
ログイン後にコピー

ほんの数行のように見えますが、理解するのは簡単ではありません (これが私がlaravelを好む理由です。コードはシンプルでエレガントですが、ほとんどの人はそれを理解できません) 、笑)

まずは、 について簡単に説明します。

次に、メソッドは、匿名関数 $destination を受け取る必要があります。 どのような匿名関数かについては、今はそのままにしておいて、後で確認することができます。一文ずつ説明しましょう

rree
それでは?
もう、これですべての作業は完了です。非常にエレガントな (不正な) コードではないでしょうか? (笑) 次に、この array_reduce が返す魔法の関数に焦点を当てます。$request を渡すだけです。それにすべてのミドルウェアを渡しますか?

array_reduce($arr, 'funcA',5) はほぼ同等で、2 番目のパラメータは関数名の文字列にすることができます

/** * Run the pipeline with a final destination callback.   *   * @param  \Closure  $destination   * @return mixed */public function then(Closure $destination){        $firstSlice = $this->getInitialSlice($destination);        $pipes = array_reverse($this->pipes);        return call_user_func(                array_reduce($pipes, $this->getSlice(), $firstSlice),         $this->passable);    );}
ログイン後にコピー

意味だけ理解してください

ソースコードに戻って、2 番目のパラメータは関数名に渡されますcode Oneは関数で、$this->getSlice()を実行して得られる関数です。このgetSliceメソッドを見てみましょう

これを見たときはちょっとクラクラしてしまいました。なんてこった!

これを単純化しています。つまり、$this->getSlice() を呼び出した後、関数 B であると仮定して関数を取得します。関数 B は 2 つのパラメーターを受け取り、関数 C を返します

このプロセスを大まかにシミュレートしてみましょう

段落 プロセスをわかりやすく説明するために偽のコードを示します:

function haha($stack, $middleware) {    return function($param) use ($stack, $middleware){        //do something     };}function fake_array_reduce($middlewares, $func, $inital=null) {    $temp = $initial;    //假设传递进来的函数$func = 'haha'    foreach($middlewares as $middleware) {        $temp = $func($temp, $middleware);    }    return $temp;}
ログイン後にコピー

这个过程的基本流程如上,haha返回了一个空函数(实际上肯定不是),我只是为了说明每次都返回一个函数作为下一次迭代的参数,而并没有执行任何其它功能,按照上面的代码,最后执行完fake_array_reduce会得到一个函数,这个函数接收一个参数。
所以再回过头来看
call_user_func(array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable);
实际上就是相当于调用了array_reduce最后一次迭代返回的函数,然后给这个函数传递了一个参数$this->passable
所以,这时候我们需要关注最后一次返回的函数是什么,看看源码关键是这段

 return function($stack, $pipe) {    return function($passable) use ($stack, $pipe) {        if($pipe instanceof Closure) {            return call_user_func($pipe, $passable, $stack);        } else {            //..        }    }}
ログイン後にコピー

每次迭代传入了当前的$pipe和上一次迭代返回的函数


IMG_0687.JPG


由上图所示
由于把pipes先反转了一下,所以最后一次迭代array_reduce得到的函数f3所use的是($stack=f2, $pipe=$middleware[0])
那么call_user_func(f3,$this->passable)相当于是

return call_user_func($middleware[0]->handle, $this->passable, f2);
ログイン後にコピー

仔细想想,middleware里面的handle方法

public function handle($request, Closure $next) {    //...    return $next($request);}
ログイン後にコピー

在这里就相当于就是return f2($request)
也就相当于return call_user_func($middleware[1]->handle, $request, f1)
而这个$request是经过middleware[0]处理过后传递过来的。
……
这个过程比较绕,需要大家自己再画图理解一下,比如源代码里用到的onion(洋葱),$stack(栈),这些单词可以帮助大家更好地理解这个过程。
所以return call_user_func($pipes, $this->getSlice(), $this->passable)就会把$request请求按middleware定义的先后顺序,流水线处理,中间件处理完了之后再传递给$this->dispatchToRouter()这个方法处理(这又是一个抽象),从而得到最后的响应结果。

理解pipeline需要理解 闭包 栈等概念,熟悉了pipeline会对理解php的新特性有比较大的帮助。

That's all thanks

来自: http://www.jianshu.com/p/3c2791a525d0

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート