nunomaduro/curryable
Laravel package by Nuno Maduro that lets you curry class methods, so multi-argument calls become chainable partial applications. Add the Curryable trait and call methods step by step, e.g. Calculator::add(1)(2), for cleaner functional-style PHP.
Fund it as developer productivity, not as a feature. Curryable has no customer-visible surface. Its value is removing closure boilerplate in configuration-heavy internal code: formatter chains, pricing rules, validation pipelines, report/query builders, and test factory builders. Attach adoption to a refactor already on the roadmap (rules-engine cleanup, pipeline tightening, collapsing callback sprawl in a domain service). If no such initiative exists this quarter, defer it — there is no forcing function and no roadmap slot to allocate.
A build-vs-buy call with a cheap, reversible exit. The package is a trait plus reflection-based arity detection, a few hundred lines total. Replacement cost is roughly a 20–50-line internal wrapper around native closures, so approve a spike without procurement — but do not treat it as a platform dependency. Vendor the concept; whether you vendor the package stays a low-stakes, easily undone decision.
Risk posture: acceptable as a leaf dev dependency, unacceptable on a critical path. MIT license, ~175 stars, single maintainer, zero recorded dependents. That combination justifies a pilot, not a standard. Hard rule: keep it out of auth, payments, and PII handling — not because the package is unsafe (no I/O, no serialization, no network surface) but because a single-maintainer utility with no field-tested dependents cannot justify third-party risk where a hand-written closure costs thirty lines.
Scope decisions, not just adoption decisions. Approve it for deliberately chosen modules where the same callable is re-bound with a stable leading argument at three or more call sites. Forbid it in controllers, models, request hot paths, and across module boundaries where readers lose the argument-order context. Approve pilots; do not mandate a company-wide convention.
Engineering-velocity framing for the business case. Expected wins: narrower diffs, less duplicated closure code, faster iteration in test builders and pipeline stages. Expected costs: a readability tax, a silent-partial-application bug class, and degraded static-analysis inference. Net value lands positive only in teams already fluent in currying semantics — that is a hiring/team-profile input to the decision, not a footnote.
Consider it when:
fn, and higher-order functions — the friction they feel is verbosity, not comprehension.Look elsewhere — or write the ~20–50 lines yourself — when:
strlen(...)), and a plain closure cover most partial-application needs; reach for curry only when the same callable is re-bound at three or more sites.Closure returned where a value was expected, TypeError surfacing frames later) is expensive to debug for readers who don't hold the semantics in their head.Closure/mixed and lose parameter hints after the first application; broad @phpstan-ignore sprinkling is a signal to shrink scope, not suppress harder.For executives — one paragraph: Curryable is a small, MIT-licensed developer utility that lets engineers pre-configure a function's leading arguments once and reuse the result, instead of re-writing near-identical closures at every call site. It has no customer-facing surface and no runtime infrastructure: no service provider, no config, no migration. The realistic upside is narrower diffs and less duplicated glue code in internal modules — pricing rules, validation pipelines, report builders, test fixtures. The realistic downside is bounded: it costs an afternoon to evaluate, it is a few hundred lines we could replace ourselves, and we will deliberately keep it out of auth, payments, and PII paths. Recommendation: approve a timeboxed pilot on one already-planned refactor; do not make it a house standard.
For engineering leads — the operational summary: Install is a single composer require with nothing to register. The whole API is one curry() function and one Curryable trait. Three adoption rules carry most of the value: (1) argument order is decided once — volatile argument first, payload last; (2) curry at wiring time in a service provider or factory, never inside a request handler, queue job, or Collection::map, so reflection is paid once; (3) import through a single internal App\Support\Functional\Curry wrapper that re-exports the package function, pins the version, and adds a terminal-application guard that throws when a callable is still partially applied. That wrapper is the exit path — if upstream goes quiet, it becomes a one-file change.
For the sponsoring product owner — what you get and what you owe: You get faster iteration on internal plumbing work that already appears on the roadmap, and a cheap experiment with a clear kill switch. You owe three things: a named owner for the wrapper file, a short ADR line documenting the silent-partial-application hazard and the argument-order convention, and acceptance that adoption stays scoped to chosen modules rather than spreading by convention. Do not greenlight this as a platform bet; greenlight it as a refactor accelerant with a 30-day check-in.
How can I help you explore Laravel packages today?