sanmai/pipeline
sanmai/pipeline is a fluent, memory-efficient PHP library for processing any iterable with lazy generators. Chain map, filter, reduce, zip, and more for readable pipelines that handle large or infinite collections without exhausting memory.
foreach/generator code used for imports, exports, feed ingestion, and report generation. At Apache-2.0 with no transitive dependency risk, the "buy" cost is a composer require and a code-review.->get() on a large result set (full-table exports, CSV/NDJSON processing, audit-log scans, sitemap or feed builds) can ship without raising PHP memory limits or adding chunking logic to every job. This is a direct enabler for roadmap items currently blocked on "too much data in memory."take()->map()->filter()->fold()) collapses multi-screen transformation blocks into a reviewable sequence. Fewer intermediate arrays and loop variables means fewer off-by-one and key-collision defects — measurable as reduced defect rate on ingestion/reporting tickets.chunkBy/chunk for batched writes and rate-limited API fan-out; cursor() for resumable, partial consumption; zip/unpack for transposing parallel sources.Adopt when most of the following hold:
iterable, is large, unbounded, or streamed from a DB cursor, file handle, or HTTP paginator.Look elsewhere when:
Illuminate\Support\LazyCollection already covers the majority of this surface with first-party support, framework conventions, and a maintenance guarantee. Introducing a second lazy-collection vocabulary into a Laravel codebase is a real cognitive tax; the justification has to be the specific gaps — weighted reservoir sampling, online variance, cursor(), unpack/tuple transposition.For executives: A small, permissively licensed PHP utility that lets us process large data sets in constant memory instead of loading them whole. It is a tactical enabler for a handful of roadmap items currently blocked on memory limits, costs nothing to license, and is isolated behind our own wrapper so it is cheap to remove. It is not a platform bet — we are not adopting a vendor, we are adopting a well-tested helper.
For engineering leadership: It removes repeated bespoke generator code from ingestion and reporting paths, and it ships with the quality signals we normally ask for in-house — full line coverage, mutation testing, PHPStan/Psalm at strict levels, and documentation kept in sync with the public API. Two risks we manage explicitly: (1) it is effectively single-maintainer with no downstream dependents, so we pin the version and confine usage to a small set of boundary classes; (2) its mutable, non-rewindable semantics differ from LazyCollection, so we standardise on one idiom per codebase and document the "consume it or nothing happens" rule in the PR template.
For the engineering team: One rule — use it in jobs, commands, importers, and exporters, not in domain code or controllers. Wrap it. If a chain needs to be re-read, use cursor() or materialise with toList(); never iterate a pipeline twice. Prefer toList()/toAssoc() over iterator_to_array() to avoid silent key collisions.
Decision requested: Approve a time-boxed pilot on one ingestion path and one report builder, measured on peak memory and code volume, with the wrapper in place from day one. If the pilot does not show a clear win over LazyCollection, we drop it and keep the wrapper.
How can I help you explore Laravel packages today?