Порекомендуйте плагин конвейера PHP League\Pipeline

задняя часть PHP Шаблоны проектирования Laravel

Шаблон проектирования конвейера

Водопроводная труба слишком длинная, если одна часть сломана, она будет протекать, и это не способствует изгибу и повороту в сложных условиях. Поэтому мы разделим водопроводные трубы на очень короткие участки, а затем максимально увеличим размер труб, чтобы они выполняли различные функции, адаптировались к местным условиям и собирали их вместе для удовлетворения самых разных потребностей.

Отсюда делается вывод, что шаблон проектирования Pipeline состоит в том, чтобы разрезать сложные и длительные процессы на небольшие процессы и небольшие задачи. Каждая задача с минимальной количественной оценкой может быть повторно использована для формирования сложных и разнообразных процессов путем сборки различных небольших задач.

Наконец, «вход» вводится в конвейер, и ввод обрабатывается (обрабатывается, фильтруется) в соответствии с каждой небольшой задачей, и, наконец, выводится результат, соответствующий потребностям.

Сегодня я в основном изучаю «Конвейер» и, кстати, рекомендую PHP-плагин:league/pipeline.

gulp

Впервые я познакомился с понятием «труба», изgulpиспользование.

gulpоснован наNodeJSавтоматическое выполнение задач, которое она может автоматизироватьJavascript,sass,lessНапример, тестирование файлов, проверка, слияние, сжатие, форматирование, автоматическое обновление браузера, создание файла развертывания и повторение указанных шагов после отслеживания изменений файла. В реализации она опирается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' ]);

два вышеtaskв основном будетless,всеjsФайлы анализируются, сжимаются, выводятся и выполняются другие операции обработки, а затем сохраняются в соответствующей папке; вывод каждой операции является вводом следующей операции, как конвейер.

Illuminate\Pipeline

Промежуточное ПО в среде Laravel должно использоватьIlluminate\PipelineЧтобы добиться этого, я изначально хотел написать свою интерпретацию исходного кода «Laravel Middleware», но обнаружил, что в Интернете уже есть много сообщений, поэтому в этой статье я кратко объясню, как его использовать.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;
        });
}

Для анализа исходного кода можно порекомендовать прочитать эту статью, анализ достаточно тщательный:

Реализация компонента Laravel PipelineWoohoo.in video.top/article/hot...

League\Pipeline

лицевой стороной вверхgulpиIlluminate\PipelineПростое использование просто говорит нам о том, что «конвейер» широко используется. Если мы позволим себе написать аналогичный плагин, я не думаю, что это должно быть сложно.

Ниже я беруLeague\PipelineПлагин, чтобы взглянуть на его исходный код, чтобы увидеть, как он реализован.

Кратко

Этот пакет обеспечивает реализацию Plug and Play шаблона конвейера. Это архитектурный шаблон, который инкапсулирует последовательные процессы. При использовании он позволяет смешивать и сопоставлять операции и конвейеры для создания новых цепочек выполнения. Шаблон конвейера часто сравнивают с производственная линия, где каждый этап выполняет определенную операцию с данной полезной нагрузкой/предметом.Этапы могут воздействовать, манипулировать, украшать или даже заменять полезную нагрузку.

If you find yourself passing results from one function to another to complete a series of tasks on a given subject, you might want to convert it into a pipeline.

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

результат операции

Расшифровка исходного кода

Весь плагин состоит из этих файлов:

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

Этот интерфейс в основном использует идею цепного программирования, непрерывно добавляя конвейерную «трубу», а затем добавляя магический метод, чтобы заставить работать входящие параметры.

Давайте посмотрим, что делает этот волшебный метод:

mixed __invoke ([ $... ] )Метод __invoke() автоматически вызывается при попытке вызвать объект способом, вызывающим функцию.

Ссылка из:PHP.net/manual/this/com…как:

<?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. Добавьте и соберите каждую «трубу» трубопровода;
  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 для написания простого фреймворка, и я тоже буду обращаться к Laravel.League\PipelineВведен в основу для использования.

"Продолжение следует"