Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Curryable Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Curryable is a framework-agnostic micro-utility — one curry() function and one Curryable trait — that converts any callable into a chain of single-argument functions. It registers no service provider, publishes no config, ships no facade or migration, and has no I/O, serialization, or network surface. Architecturally it is a leaf dependency: it composes with native closures and Laravel's container, Pipeline, and Collection::map, but nothing depends on it in turn. That makes it safe to adopt in isolation and trivial to remove. Its natural home is configuration-heavy internal code — formatter chains, pricing resolvers, validation pipelines, report builders, test factory builders — not controllers, models, or request hot paths.

Integration feasibility. The entire evaluation surface is a README that fits on one screen plus a few-hundred-line source tree. Install is composer require nunomaduro/curryable; there is nothing to wire. A meaningful spike — curry one existing re-wrapped closure, confirm partial application returns a Closure and full application returns a value, add declare(strict_types=1) — fits in an afternoon. The real integration work is not technical but organizational: locking an argument-order convention (volatile argument first, payload last), enforcing wiring-time binding, and standing up an internal wrapper.

Technical risk. The dominant risk is the silent-partial-application hazard: under-application does not throw, it returns a Closure that fails several frames downstream as a TypeError in unrelated code. Second is static-analysis degradation — PHPStan and Psalm infer Closure/mixed across curried call sites, and broad @phpstan-ignore suppression is a signal to shrink scope, not suppress harder. Third is arity detection via reflection: variadics, default values, named arguments, union/intersection types, by-reference parameters, and __invoke objects are exactly where reflection-based counting breaks, and a bad count produces a partial application that never completes. Fourth is the maturity profile — MIT, ~175 stars, single maintainer, zero recorded dependents, meaning no one has field-tested the edge cases against real code. The package is a few hundred lines, so replacement cost is roughly a 20-line internal wrapper; that caps the downside but does not eliminate the bug class.

Key questions.

  • Is there a concrete, named refactor this attaches to — rules-engine cleanup, pipeline tightening, callback sprawl in a domain service — or is this adoption without a forcing function?
  • Are the engineers already fluent in currying semantics? Net value lands positive only for teams where the friction is verbosity, not comprehension.
  • Do we have a measurable partial-application pattern (same callable re-bound with a stable leading argument at three or more call sites), or is this a solution looking for a problem?
  • Will an internal wrapper (App\Support\Functional\Curry, with an apply() guard) land before any application code imports the package function?
  • Does the team accept the scope boundary as a rule — chosen modules only, forbidden in auth, payments, PII handling, controllers, models, and request hot paths?
  • What is our PHP minor-version position, and is a bump treated as a reviewable event with characterization tests in CI?

Integration Approach

Stack fit. Targets Laravel 10/11 on PHP 8.2+. Nothing about the runtime contract conflicts with the framework; the package is dependency-free and test-friendly. The important fit criterion is usage pattern, not stack version: curry at wiring time (service provider, factory, singleton binding) so reflection cost is amortized, and never inside Collection::map, queue jobs, or request handlers where construction re-reflects on every invocation.

Migration path. Brownfield and incremental by design — no coexistence shim, no dual-write, no data migration. The path is: land the wrapper → pick one candidate closure already re-wrapped at multiple call sites → curry it → measure diff size and readability → expand module by module. Existing native fn ($x) => ... and first-class callable syntax stay in place; currying is introduced only where the same callable is re-bound three or more times. There is no cutover date and no flag day, which is the migration's strongest property: any module can be reverted by inlining the closure back.

Compatibility. Two compatibility fronts. Runtime: the package must track PHP's argument-handling semantics (named arguments, never, true, union types), and a single-maintainer project may lag a PHP minor release — pin with a caret constraint and let Dependabot/Renovate plus a characterization-test CI job catch drift. Tooling: static analysis loses parameter hints after the first application, so baseline PHPStan/Psalm noise before wide adoption and confine any suppressions to the wrapper file. Debugging shows curried callables as anonymous functions with low-information frames; named variables mitigate this and should be a review convention, not a suggestion.

Sequencing.

  1. Approve a spike, not an adoption. One afternoon, one closure, php artisan tinker.
  2. Land the internal wrapper (App\Support\Functional\Curry) with the terminal-application apply() guard. This is the abandonment insurance and the one-file swap point.
  3. Write characterization tests for the argument shapes the team actually uses — variadics, defaults, named args, unions, __invoke. We are the field testing; zero dependents means the burden is ours.
  4. Publish a short ADR: argument-order convention, permitted modules, forbidden paths, the silent-partial-application line item.
  5. Pilot in exactly one module attached to an initiative already on the roadmap.
  6. Expand only if the diff-size win is observable and the readability tax is contained. Do not mandate a company-wide convention.

Operational Impact

Maintenance. Low, and bounded. The dependency itself is a few hundred lines with no transitive graph; keeping it current is a caret constraint plus automated PRs. Our own maintenance burden is the wrapper, the ADR, and the characterization test suite — all deliberately in our code, not application code, which is what preserves the exit path. If upstream goes quiet, MIT licensing makes a fork or a vendored ~20-line helper entirely realistic. Treat PHP version bumps as reviewable events with the characterization suite as the gate.

Support. No vendor, no SLA, no commercial support — a single maintainer and zero recorded dependents. Internally that means support is self-service: the README, the test suite (the de facto specification), and our ADR. Onboarding docs matter more than usual here because curried call sites are harder to grep and harder to trace; a reader who does not know the argument-order convention cannot follow the code. That is a documentation obligation we take on, not one we inherit.

Scaling. Technical scaling is a non-issue at application scale — it is a pure function-composition helper with no runtime resource footprint. The scaling constraint is cognitive and spatial: readability debt grows with the number of engineers who have to read curried code without having written it, and greppability degrades proportional to how far currying spreads across module boundaries. The realistic ceiling is a handful of deliberately chosen modules owned by teams fluent in higher-order functions. Under Octane and long-lived workers, verify curried callables are not accumulating unboundedly — that is an audit item, not a blocker.

Failure modes. Ranked by likelihood:

  • Silent partial application — the dominant class. Under-application returns a Closure; the TypeError surfaces frames away. Mitigations in order: the apply() guard, a test assertion that curried callables are fully applied, a code-review checklist item, typed variables. This deserves an ADR line.
  • Arity miscount on exotic signatures — variadics, named arguments, unions, by-reference params. Produces a partial application that never completes. Mitigation: characterization tests written before reliance.
  • Static-analysis erosion — silent loss of type inference, then a slow accretion of suppressions. If fixes become scattered @phpstan-ignore comments, shrink scope.
  • Reflection in hot paths — construction inside loops or per request. Mitigation: bind at wiring time, enforce in review.
  • Convention drift on argument order — someone binds payload-first, and every downstream call site reads backwards. Mitigation: one written convention, enforced early.
  • Upstream lag on a PHP minor — mitigated by pinning and CI.

Explicitly out of scope: auth, payments, and PII handling. Not because the package is unsafe — it has no I/O, serialization, or 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.

Ramp-up. Shallow to install, moderate to use well. Install and first curried closure: under an hour for anyone comfortable with fn and higher-order functions. Productive, convention-following use: a week, gated on the ADR and the wrapper landing first. Team-wide literacy: the real cost. The failure mode to watch for is a team that finds the syntax easy and the semantics hard — curried code that reads fine to its author and is opaque to its next reader. That is a hiring and team-profile input to the decision, not a detail to defer. Budget one engineer-day for the spike plus wrapper plus characterization tests, and frame the expected return as narrower diffs, less duplicate closure code, and faster iteration in test builders — developer-productivity value attached to a refactor already on the roadmap. If no such initiative exists this quarter, defer; there is no forcing function and no roadmap slot to allocate.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle