定制 rockett/pipeline 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

rockett/pipeline

Composer 安装命令:

composer require rockett/pipeline

包简介

A plug and play pipeline implementation.

README 文档

README

GitHub License Packagist Version Packagist Downloads Forgejo Workflow Status

Provides an implementation of the pipeline pattern with additional processors for conditional interruption and stage tapping.

This package was originally forked from League's excellent pipeline package.

Installation

composer require rockett/pipeline

Requires PHP 8.3+.

Quick Start

use Rockett\Pipeline\Pipeline;

$pipeline = (new Pipeline)
    ->pipe(fn($x) => $x * 2)
    ->pipe(fn($x) => $x + 1);

echo $pipeline->process(10); // Outputs: 21

Note

PHP 8.5+ Pipe Operator: With PHP 8.5 introducing the native pipe operator, basic sequential operations can now be achieved without a package. However, this library still provides value through reusable pipeline objects, conditional interruption (continueWhen/continueUnless), stage tapping for observability (beforeEach/afterEach), and a fluent API for composing complex processing workflows that go beyond simple function chaining.

Pipeline Pattern

The pipeline pattern lets you compose sequential operations by chaining stages. Each stage receives a traveler (payload), processes it, and passes the output to the next stage. Internally, this is equivalent to:

$output = $stage3($stage2($stage1($traveler)));

Immutability

Pipelines are implemented as immutable stage-chains, contracted by the PipelineContract interface. When you add a new stage, the pipeline will be cloned with the new stage added in. This makes pipelines easy to re-use, and minimizes side-effects.

Usage

Operations in a pipeline (stages) can accept anything from the pipeline that satisfies the callable type-hint. So closures and anything that's invokable will work.

$pipeline = (new Pipeline)->pipe(static function ($traveler) {
  return $traveler * 10;
});

Class-based stages

Classes can be used as stages by implementing StageContract and an __invoke method:

use Rockett\Pipeline\Pipeline;
use Rockett\Pipeline\Contracts\StageContract;

class TimesTwoStage implements StageContract
{
  public function __invoke($traveler)
  {
    return $traveler * 2;
  }
}

$pipeline = (new Pipeline)
  ->pipe(new TimesTwoStage)
  ->pipe(new PlusOneStage);

$pipeline->process(10); // Returns 21

You can create custom stage contracts to type-hint the traveler and return type.

Re-usability

Pipelines can be re-used as stages within other pipelines, enabling composable architectures:

$processApiRequest = (new Pipeline)
  ->pipe(new ExecuteHttpRequest) // B
  ->pipe(new ParseJsonResponse); // C

$pipeline = (new Pipeline)
  ->pipe(new ConvertToPsr7Request) // A
  ->pipe($processApiRequest) // (B and C)
  ->pipe(new ConvertToDataTransferObject); // D

$pipeline->process(new DeleteArticle($postId));

Pipeline Builders

While pipelines are immutable by design, there are scenarios where you need to conditionally compose stages before building the pipeline. Pipeline builders solve this by providing a mutable container for collecting stages, which is then converted to an immutable pipeline:

use Rockett\Pipeline\Builder\PipelineBuilder;

$builder = new PipelineBuilder;

$builder->add(new ValidateInput)
  ->add(new SanitizeData);

if ($config->get('logging.enabled')) {
  $builder->add(new LogRequest);
}

if ($user->hasPermission('admin')) {
  $builder->add(new EnrichWithAdminData);
}

$builder->add(new TransformToResponse)
  ->add(new CompressOutput);

$pipeline = $builder->build();
$result = $pipeline->process($request);

Once build() is called, you have an immutable pipeline that can be reused or passed around safely without concerns about side-effects from modifications.

Processors

Processors handle iteration through stages and enable additional features like conditional interruption and stage tapping.

Caution

As of v4.1, these processors are deprecated and slated for removal in v5:

  • InterruptibleProcessor – use Processor with continueUnless()/continueWhen()
  • TapProcessor – use Processor with beforeEach()/afterEach()
  • InterruptibleTapProcessor – use Processor with combined methods

FingersCrossedProcessor (Default)

Basic sequential processing with no early exit capability (throw an exception to stop).

use Rockett\Pipeline\Pipeline;
use Rockett\Pipeline\Processors\FingersCrossedProcessor;

$pipeline = new Pipeline(new FingersCrossedProcessor);
// Or simply: new Pipeline() – FingersCrossedProcessor is the default

Processor

The Processor supports conditional interruption (early exit) and stage tapping (callbacks before/after each stage), configured fluently with method-chaining:

use Rockett\Pipeline\Processors\Processor;

$processor = (new Processor())
    ->continueUnless(fn($traveler) => $traveler->hasError())
    ->beforeEach(fn($traveler) => $logger->info('Processing:', $traveler->toArray()))
    ->afterEach(fn($traveler) => $metrics->increment('pipeline.stage.completed'));

$pipeline = (new Pipeline($processor))
    ->pipe(new ValidateInput)
    ->pipe(new ProcessData)
    ->pipe(new SaveToDatabase);

Features can be composed via method chaining:

  • continueUnless(callable) – exit when callback returns true
  • continueWhen(callable) – exit when callback returns false
  • invert() – invert the interrupt condition
  • beforeEach(callable) – execute callback before each stage
  • afterEach(callable) – execute callback after each stage

Exiting pipelines early

Use interrupt methods to exit pipelines early based on conditions:

use Rockett\Pipeline\Processors\Processor;

$processor = (new Processor())
    ->continueUnless(fn($traveler) => $traveler->hasError());

$pipeline = (new Pipeline($processor))
    ->pipe(new ValidateInput)
    ->pipe(new ProcessData)
    ->pipe(new SaveToDatabase);

$output = $pipeline->process($request);

In this example, when $traveler->hasError() returns true, the pipeline exits early.

Available interrupt methods:

// Exit when condition is true
$processor = (new Processor())
    ->continueUnless(fn($traveler) => $traveler->hasError());

// Exit when condition becomes false
$processor = (new Processor())
    ->continueWhen(fn($traveler) => $traveler->isValid());

// Invert the condition
$processor = (new Processor())
    ->continueWhen(fn($traveler) => $traveler->isValid())
    ->invert(); // Now exits when isValid() returns false

Invoking actions on each stage

Use tap methods to invoke callbacks before and/or after each stage for logging, metrics, or debugging:

use Rockett\Pipeline\Processors\Processor;

$processor = (new Processor())
    ->beforeEach(fn($traveler) => $logger->info('Processing:', $traveler->toArray()))
    ->afterEach(fn($traveler) => $metrics->increment('pipeline.stage.completed'));

$pipeline = (new Pipeline($processor))
    ->pipe(new StageOne)
    ->pipe(new StageTwo)
    ->pipe(new StageThree);

$output = $pipeline->process($traveler);

Per-stage conditions

Stages can optionally implement a condition method to control whether they should execute. If the condition returns false, the stage is skipped and the traveler is passed to the next stage untouched.

class ProcessPaymentStage implements StageContract
{
  public function condition($traveler): bool
  {
    return $traveler->requiresPayment();
  }

  public function __invoke($traveler)
  {
    return $traveler->processPayment();
  }
}

Note

Condition-checking is done after the beforeEach stage tap.

Handling Exceptions

The package won't catch exceptions. Handle them in your code, either inside a stage or when calling the pipeline.

$pipeline = (new Pipeline)->pipe(
  static fn () => throw new LogicException
);

try {
  $pipeline->process($traveler);
} catch(LogicException $e) {
  // Handle the exception.
}

Testing

composer test

License

Pipeline is a fork of [League\Pipeline] by Frank de Jonge. It is licensed under the ISC License, with the original code retaining its MIT License. See LICENSE.md for details.

Contributing

Contributions are welcome – if you have something to add to this package, or have found a bug, feel free to submit a pull request for review.

rockett/pipeline 适用场景与选型建议

rockett/pipeline 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 189k 次下载、GitHub Stars 达 4, 最近一次更新时间为 2021 年 02 月 04 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「pattern」 「pipeline」 「composition」 「design pattern」 「sequential」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 rockett/pipeline 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 rockett/pipeline 我们能提供哪些服务?
定制开发 / 二次开发

基于 rockett/pipeline 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 189k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 4
  • 点击次数: 19
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 4
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-02-04