Status: Accepted
Date: 2025-11-20
Author: Walmir Silva
Supersedes: N/A
The original ProcessorPipeline (v1.x–v1.3.2) used a mutable Pipeline class where pipe() modified the internal array in-place. This created several problems:
- Race conditions: Shared pipeline instances modified concurrently in async/fiber contexts produced non-deterministic processor ordering.
- Test isolation: Test suites that reused pipeline fixtures experienced ordering leaks between test methods.
- Composition safety: Building a "base pipeline" and extending it for specific use-cases mutated the base, breaking other consumers.
Starting with v4.0.0, Pipeline is declared final readonly class. The pipe() method is replaced by withProcessor() which returns a new Pipeline instance. The original is never modified.
// v1.x (mutable)
$pipeline->pipe(new TrimProcessor()); // mutates $pipeline
// v4.0 (immutable — ARFA 1.3 P1)
$extended = $pipeline->withProcessor(new TrimProcessor()); // new instancePrinciple 1 (Immutable State Transformation):
∀s ∈ States, ∀t ∈ Transformations: t(s) → s' where s ≠ s' ∧ s.immutable = true
The Pipeline is a state object. Adding a processor is a transformation that must produce a new pipeline, leaving the original unchanged.
- Zero race conditions on shared pipeline instances
- Full test isolation without
setUp()reconstruction - Safe composition: base pipelines can be extended freely
- Aligns with PHP 8.4+
readonly classlanguage support
- Marginal memory overhead from cloning processor arrays (negligible for typical pipeline sizes of 3–15 processors)
- Existing v1.x code using
pipe()requires migration towithProcessor()
ProcessorBuilder::buildPipeline()already produced a new pipeline per call, so builder-based code is unaffected
- Copy-on-write with
clone: Rejected — PHP's clone semantics for arrays are value-copy, which is whatreadonlyalready provides. No benefit over the simpler approach. - Freezable pattern (
$pipeline->freeze()): Rejected — adds runtime state tracking, violates Principle 1, and creates a temporal coupling anti-pattern.
- ARFA 1.3 Specification §4.4 (ProcessorPipeline Type Definition)
- Okasaki, C., "Purely Functional Data Structures", Cambridge University Press, 1999
- KaririCode Standard Specification V4.0 §3.1 (Immutability Requirements)