ホームページ >バックエンド開発 >PHPチュートリアル >PHPパイプラインプラグインLeague\Pipelineの解析について

PHPパイプラインプラグインLeague\Pipelineの解析について

不言
不言オリジナル
2018-07-10 14:30:582617ブラウズ

この記事では、主に PHP パイプライン プラグイン League\Pipeline の分析を紹介します。このプラグインは一定の参考値があります。ここで共有します。必要な友人は参考にしてください。

パイプライン設計パターン

水道管は長すぎるため、一部が破損すると水漏れが発生し、複雑な環境での曲げや回転には適していません。そこで、水道管を非常に短い管に分割し、地域の状況に合わせて、さまざまな機能を持たせるために管のサイズを最大化し、組み合わせてさまざまなニーズに対応します。

これは、複雑で長いプロセスを小さなプロセスとタスクに分割するという Pipeline の設計パターンにつながります。最小限に定量化された各タスクは、さまざまな小さなタスクを組み立てることによって、複雑で多様なプロセスを形成するために再利用できます。

最後に、パイプラインに「入力」を導入し、それぞれの小さなタスクに応じて入力を操作(処理、フィルター)し、最終的にニーズに合った結果を出力します。

今日は主に「パイプライン」について勉強します。ちなみに、PHP プラグインは league/pipeline をお勧めします。

gulp

私が「パイプ」の概念について初めて知ったのは、gulp を使用したときでした。

PHPパイプラインプラグインLeague\Pipelineの解析について

gulp は、NodeJS に基づく自動タスク ランナーです。Javascript、テストを自動的に完了できます。 、チェック、マージ、圧縮、フォーマット、ブラウザの自動更新、sassless およびその他のファイルのデプロイメント ファイルの生成、変更後に指定された手順を繰り返すためにファイルを監視します。実装に関しては、Unix オペレーティング システムのパイプのアイデアを利用しており、前のレベルの出力が直接次のレベルの入力になるため、操作が非常に簡単になります。

var gulp = require('gulp');
var less = require('gulp-less');
var minifyCSS = require('gulp-csso');
var concat = require('gulp-concat');
var sourcemaps = require('gulp-sourcemaps');

gulp.task('css', function(){
  return gulp.src('client/templates/*.less')
    .pipe(less())
    .pipe(minifyCSS())
    .pipe(gulp.dest('build/css'))
});

gulp.task('js', function(){
  return gulp.src('client/javascript/*.js')
    .pipe(sourcemaps.init())
    .pipe(concat('app.min.js'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('build/js'))
});

gulp.task('default', [ 'html', 'css', 'js' ]);

上記の 2 つの タスクは主に、less およびすべての js ファイルに対する解析、圧縮、出力、その他の処理操作を行います。対応するフォルダーに保存すると、パイプ内の水の流れと同様に、各ステップの出力が次のステップの入力になります。

IlluminatePipeline

Laravel フレームワークのミドルウェアは Illuminate\Pipeline を使用して実装されています。もともと「Laravel ミドルウェア」のソース コードの解釈について書きたかったのです。しかし、インターネット上にはすでに多くの記事が説明されていることがわかったので、この記事では Illuminate\Pipeline の使用方法について簡単に説明します。

デモを書く

public function demo(Request $request)
{
    $pipe1 = function ($payload, Closure $next) {
        $payload = $payload + 1;
        return $next($payload);
    };

    $pipe2 = function ($payload, Closure $next) {
        $payload = $payload * 3;
        return $next($payload);
    };

    $data = $request->input('data', 0);

    $pipeline = new Pipeline();

    return $pipeline
        ->send($data)
        ->through([$pipe1, $pipe2])
        ->then(function ($data) {
            return $data;
        });
}


PHPパイプラインプラグインLeague\Pipelineの解析について

PHPパイプラインプラグインLeague\Pipelineの解析について

##対象者向けソースコードの分析については、この記事を読むことをお勧めします。分析は非常に徹底的です:

Laravel Pipeline コンポーネントの実装 https://www.insp.top/article/realization-of-pipeline-component- for -laravel
LeaguePipeline

上記の

gulpIlluminate\Pipeline の単純な使用法は、「Pipeline」が広く使用されていることを示しています。同様のプラグインを自分で作成するように求められた場合、それは難しくないと思います。

League\Pipeline プラグインを取り上げ、そのソース コードを見て、それがどのように実装されているかを見てみましょう。

簡単な説明

このパッケージは、パイプライン パターンのプラグ アンド プレイ実装を提供します。これは、逐次プロセスをカプセル化するアーキテクチャ パターンです。使用すると、混合することができます。操作とパイプラインを照合して、新しい実行チェーンを作成します。パイプライン パターンは、各ステージが特定のペイロード/サブジェクトに対して特定の操作を実行する生産ラインによく比較されます。ステージは、操作、操作、装飾、さらには置き換えることができますペイロード。
特定の主題に関する一連のタスクを完了するために、ある関数から別の関数に結果を渡している場合は、それをパイプラインに変換するとよいでしょう。

https://pipeline. thephpleague.com/

プラグインをインストールします

composer require league/pipeline

デモを作成します

use League\Pipeline\Pipeline;

// 创建两个闭包函数
$pipe1 = function ($payload) {
    return $payload + 1;
};

$pipe2 = function ($payload) {
    return $payload * 3;
};

$route->map(
    'GET',
    '/demo',
    function (ServerRequestInterface $request, ResponseInterface $response
    ) use ($service, $pipe1, $pipe2) {
        $params = $request->getQueryParams();

        // 正常使用
        $pipeline1 = (new Pipeline)
            ->pipe($pipe1)
            ->pipe($pipe2);

        $callback1 = $pipeline1->process($params['data']);

        $response->getBody()->write("<h1>正常使用</h1>");
        $response->getBody()->write("<p>结果:$callback1</p>");

        // 使用魔术方法
        $pipeline2 = (new Pipeline())
            ->pipe($pipe1)
            ->pipe($pipe2);

        $callback2 = $pipeline2($params['data']);

        $response->getBody()->write("<h1>使用魔术方法</h1>");
        $response->getBody()->write("<p>结果:$callback2</p>");

        // 使用 Builder
        $builder = new PipelineBuilder();
        $pipeline3 = $builder
            ->add($pipe1)
            ->add($pipe2)
            ->build();

        $callback3 = $pipeline3($params['data']);

        $response->getBody()->write("<h1>使用 Builder</h1>");
        $response->getBody()->write("<p>结果:$callback3</p>");
        return $response;
    }
);

実行結果

PHPパイプラインプラグインLeague\Pipelineの解析について

PHPパイプラインプラグインLeague\Pipelineの解析について

ソースコードの解釈

プラグ全体

PHPパイプラインプラグインLeague\Pipelineの解析について

PipelineInterface

<?php declare(strict_types=1);

namespace League\Pipeline;

interface PipelineInterface extends StageInterface
{
    /**
     * Create a new pipeline with an appended stage.
     *
     * @return static
     */
    public function pipe(callable $operation): PipelineInterface;
}

interface StageInterface
{
    /**
     * Process the payload.
     *
     * @param mixed $payload
     *
     * @return mixed
     */
    public function __invoke($payload);
}
このインターフェイスは主にチェーン プログラミングのアイデアを使用して、継続的にパイプ「pipe」を追加し、渡されたパラメーターを実行するマジック メソッドを追加します。

この魔法のメソッドの機能を見てみましょう:

mixed __invoke ([ $... ] )
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

如:

<?php class CallableClass 
{
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

返回结果:

int(5)
bool(true)

Pipeline

<?php declare(strict_types=1);

namespace League\Pipeline;

class Pipeline implements PipelineInterface
{
    /**
     * @var callable[]
     */
    private $stages = [];

    /**
     * @var ProcessorInterface
     */
    private $processor;

    public function __construct(ProcessorInterface $processor = null, callable ...$stages)
    {
        $this->processor = $processor ?? new FingersCrossedProcessor;
        $this->stages = $stages;
    }

    public function pipe(callable $stage): PipelineInterface
    {
        $pipeline = clone $this;
        $pipeline->stages[] = $stage;

        return $pipeline;
    }

    public function process($payload)
    {
        return $this->processor->process($payload, ...$this->stages);
    }

    public function __invoke($payload)
    {
        return $this->process($payload);
    }
}

其中核心类 Pipeline 的作用主要就是两个:

  1. 添加组装各个管道「pipe」;

  2. 组装后,引水流动,执行 process($payload),输出结果。

Processor

接好各种管道后,那就要「引水入渠」了。该插件提供了两个基础执行类,比较简单,直接看代码就能懂。

// 按照 $stages 数组顺利,遍历执行管道方法,再将结果传入下一个管道,让「水」一层层「流动」起来
class FingersCrossedProcessor implements ProcessorInterface
{
    public function process($payload, callable ...$stages)
    {
        foreach ($stages as $stage) {
            $payload = $stage($payload);
        }

        return $payload;
    }
}

// 增加一个额外的「过滤网」,经过每个管道后的结果,都需要 check,一旦满足则终止,直接输出结果。
class InterruptibleProcessor implements ProcessorInterface
{
    /**
     * @var callable
     */
    private $check;

    public function __construct(callable $check)
    {
        $this->check = $check;
    }

    public function process($payload, callable ...$stages)
    {
        $check = $this->check;

        foreach ($stages as $stage) {
            $payload = $stage($payload);

            if (true !== $check($payload)) {
                return $payload;
            }
        }

        return $payload;
    }
}

interface ProcessorInterface
{
    /**
     * Process the payload using multiple stages.
     *
     * @param mixed $payload
     *
     * @return mixed
     */
    public function process($payload, callable ...$stages);
}

我们完全也可以利用该接口,实现我们的方法来组装管道和「过滤网」。

PipelineBuilder

最后提供了一个 Builder,这个也很好理解:

class PipelineBuilder implements PipelineBuilderInterface
{
    /**
     * @var callable[]
     */
    private $stages = [];

    /**
     * @return self
     */
    public function add(callable $stage): PipelineBuilderInterface
    {
        $this->stages[] = $stage;

        return $this;
    }

    public function build(ProcessorInterface $processor = null): PipelineInterface
    {
        return new Pipeline($processor, ...$this->stages);
    }
}

interface PipelineBuilderInterface
{
    /**
     * Add an stage.
     *
     * @return self
     */
    public function add(callable $stage): PipelineBuilderInterface;

    /**
     * Build a new Pipeline object.
     */
    public function build(ProcessorInterface $processor = null): PipelineInterface;
}

总结

无论是对不同技术的横向理解,还是基于 Laravel 或者某些开源插件,我们都能学习到技术之上的通用原理和方法。再将这些原理和方法反作用于我们的实际代码开发中。

最近闲来没事,自己参考 Laravel 去写个简易框架,也将League\Pipeline 引入到框架中使用。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

关于PHP开发中遇到的一些错误的解决方法

关于利用Vue-laravel前端和后端分离写一个博客的方法

以上がPHPパイプラインプラグインLeaguePipelineの解析についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。