petrobolos/fixed-array-functions
Fixed Array Functions offers reliable, predictable replacements for common PHP array helpers, helping Laravel and PHP developers avoid edge-case bugs and inconsistent built-in behavior when searching, filtering, mapping, and manipulating arrays with safer key and value handling.
Scope. Initial assessment of petrobolos/fixed-array-functions (repo: oliverearl/fixed-array-functions) v3.1.0 — a fluent, Laravel-Collection-compatible wrapper around PHP's SplFixedArray, now at 70+ methods. No prior assessment existed, so this establishes the baseline.
Architecture fit. This is a leaf utility dependency: no service provider, no config surface, no persistence, no I/O. It does not shape architecture and shouldn't be treated as a platform decision — it's a targeted optimization for memory- and CPU-sensitive in-process pipelines (report aggregation, exports, large numeric payload transforms in queue workers). The strategic value is that it lets us get SplFixedArray's memory profile without hand-rolled loops, which is what usually blocks this optimization in review.
Integration feasibility. High. composer require, one global helper (fixedArray()), zero infrastructure. Quality signals are genuinely strong for a package this size: 290 tests, 100% coverage claim, PHPStan Level 9 with zero errors, active Dependabot, and new governance files (CONTRIBUTING, SECURITY, issue/PR templates). 3.0 → 3.1 is explicitly backward compatible.
Technical risk.
sum/avg) is the most likely source of production defects.filter() signature change. Now passes ($value, $key). Backward compatible for closures and most callables, but a real behavioral change for anything introspecting args (func_get_args, variadics) — and it shipped in a minor.petrobolos/...) does not match the GitHub org (oliverearl/...). Needs verification before it clears supply-chain review.SplFixedArray has no amortized growth; code paths that append will pay resize costs and erase the memory win.when()/unless()/tap() return the same instance or a clone determines aliasing-bug exposure in long chains.Key questions.
illuminate/support, or is Laravel support only a CI matrix entry? (Determines usability outside Laravel services.)Collection for sum/avg/filter/map/pluck chains.when/unless/tap/pipe; partition()'s return type.json_encode, nested toArray(), Eloquent models as elements.filter() change have been minor again?Stack fit. Laravel 10–13 matrix claimed, PHP 8.x, zero infrastructure footprint — deploys with the app, no container bindings, no env vars, no migrations.
Migration path (deliberately narrow).
collect(). Pick one measurable hot path first (a nightly export or an aggregation over a large result set).ResultSet/Pipeline) whose public surface we own, backed by fixedArray() on the hot path and collect() elsewhere. Rollback becomes a one-line change, and the package API stays out of the wider codebase.Compatibility considerations. Method parity makes translations mostly mechanical, but the real breakage vector is types, not methods: return values will not be Illuminate\Support\Collection, so type hints, return declarations, and anything expecting Collection (paginators, lazy()/generator behavior) will fail. Static analysis is the safety net — PHPStan 9 upstream is fine, but our own baseline must be clean or the type deltas drown in noise. Also: never serialize these objects into queue payloads or cache.
Sequencing (~one quarter, part-time).
Maintenance. Low on our side — semver minor bumps, no config, no migrations. The real cost is upstream monitoring: the surface grew ~50% in a single release, and parity work tends to expose semantic drift over time. Budget a review slot per release; do not auto-merge.
Support. The new governance artifacts (CONTRIBUTING, SECURITY, structured issue/PR templates) are the most operationally valuable line in these notes — more than any individual method, because they give us a defect-reporting channel and a disclosure path. With no SLA, treat support as best-effort and keep a fork-ready posture (verify license terms).
Scaling. This is the entire rationale: per-worker memory headroom under PHP-FPM/queue workers, enabling larger batches or higher concurrency before OOM. The benefit is data-shape dependent — numeric, fixed-length, no per-element object overhead — and evaporates when arrays grow dynamically or hold objects. Validate on our payloads, not synthetic integer arrays.
Failure modes.
Collection (wrong aggregates, dropped keys, partition() destructuring errors) — mitigated by parity tests and the adapter boundary.SplFixedArray dumps are less readable; tap() helps, but log plain arrays, not the wrapper.Ramp-up. Low for anyone fluent in Laravel Collections — that's the package's core selling point and its strongest argument over hand-rolled loops. Plan: a short brown-bag on the memory model and the fixed-size constraint, the adapter as house style, and a one-page "when to use this vs. collect()" note. Roughly 1–2 days per engineer, plus reviewer discipline to keep it out of ordinary CRUD code.
Recommendation. Adopt conditionally: pilot one hot path behind an adapter, gated on a benchmark showing a meaningful memory win, and do not standardize this quarter. The release itself is healthy and low-risk to evaluate; the package is still young and single-maintainer. Highest-value items for us are the filter() performance work, the aggregation methods (removing the main reason we'd have dropped to raw loops), and the governance files. The 23 new methods matter less than whether parity actually holds where we use it.
How can I help you explore Laravel packages today?