gerardojbaez/money
A Laravel package for working with monetary values through an expressive API. It simplifies formatting, parsing, and converting currencies, making it easy to display prices and handle money safely in PHP code and Blade templates.
Architecture fit. gerardojbaez/money is a leaf-level formatting utility, not an infrastructure component. It is a drop-in replacement for the removed money_format() function: a small library that maps a numeric amount plus a currency code to a formatted string using a bundled table of 91 currencies and their symbols/placements. There is no service provider, no facade, no container binding, and no dependency on Laravel internals. That makes it a poor fit for anything resembling a domain money model — it does no arithmetic, no allocation/splitting, no rounding-mode control, no exchange rates, and no value-object semantics. If the requirement is "render an amount as a localized-looking string in views and PDFs," it fits in an afternoon. If the requirement is "represent and compute money correctly across the application," it is the wrong layer and should be rejected in favor of brick/money or moneyphp/money with a separate formatter.
Integration feasibility. High, with caveats. Installation is a single Composer require; usage is static calls on a small class surface. The package is PSR-4 autoloaded and has essentially no configuration. The integration work is not in wiring it up but in two other places: (1) confirming the package actually runs clean on the target PHP version, and (2) deciding whether the team accepts ownership of an archived dependency.
Technical risk. This is the dominant concern and it is not about code volume — the library is tiny — it is about lifecycle:
money_format() — the reason this package exists. Syntax is simple enough that it will likely parse and run on 8.1–8.3, but that is a hypothesis to be tested, not a guarantee. Deprecation notices (dynamic properties, implicit nullable parameters) are plausible.money_format(). money_format() was locale-aware (setlocale), used %n/%i specifiers, and produced locale-specific separators and negative-number conventions. This package produces deterministic output independent of locale. Migration will change rendered strings in ways that are correct-by-design but visible to users and to snapshot tests.₹12,34,567.89) is materially different from Western grouping (₹1,234,567.89). Symbol support and grouping support are different features; the README's "including INR" claim should be read as the former until proven otherwise. If the product has Indian users, this is a P1 verification item.Key questions for the team before adoption.
NumberFormatter/ICU is the correct tool and this package is a regression.NumberFormatter or a money value object?Stack fit. Works in any Laravel 8–11 application and any plain PHP project. It requires no Laravel-specific wiring, which cuts both ways: nothing to register, but also no configuration surface for a default currency, no Blade directive, and no validation rule. The pragmatic pattern is to wrap it in a single project-owned adapter — a small service class or helper (e.g., App\Support\MoneyFormatter) plus an optional Blade directive and a config/money.php for the application default currency. Every call site should go through the adapter, never through the vendor class directly. That single decision converts an archived dependency from a risk into a swappable implementation detail.
Migration path from money_format(). This is the primary use case and it should be treated as a codemod-plus-verification exercise, not a refactor:
money_format() call site (grep -rn "money_format") and record the format string, the locale in effect at that call, and the expected output.%n semantics cannot leak back in.setlocale(LC_MONETARY, ...)) — this is usually a net win, since those calls are global mutable state and a common source of cross-request bugs in long-running workers.Compatibility. Pin the version exactly in composer.json and vendor it. Because the repo is archived, "latest" is not a moving target — but that also means the lockfile is the only guarantee. If the package fails on the target PHP version, the fix is small and localized (typically a constructor signature or a deprecation), so a fork under the organization's namespace with a one-line patch is a reasonable outcome. Budget for that contingency rather than assuming it away.
Sequencing. (1) Decide build-vs-buy on the fork question — if we are going to fork, fork on day one and never depend on the upstream package name. (2) Run the PHP-version spike and the golden-file verification in parallel. (3) Land the adapter with no call sites. (4) Migrate call sites in batches by feature area, with the golden files as the gate. (5) Remove setlocale(LC_MONETARY) calls last, once nothing depends on them. (6) Open a follow-up ticket to evaluate NumberFormatter or brick/money as the strategic replacement — but do not block the immediate money_format() removal on it, since PHP 8 already removed the function and any app still calling it is likely already broken or pinned.
Maintenance. This is the whole story. An archived package with a 2018 release is not "stable," it is "abandoned," and the difference matters to whoever is on call. The maintenance burden is low in absolute terms — the library is a few hundred lines of currency tables and string concatenation, and currency data changes rarely — but it is nonzero and it is ours. Concretely: we own PHP-version compatibility, we own any currency-table corrections, and we own the decision log explaining why this exists. That should be a named owner in the ticket, with the adapter as the documented boundary.
Support. No vendor, no maintainer, no issue triage, 59 stars and a community too small to have a de facto forum. Internal support is the only support. The mitigation is that the code is fully readable — a competent engineer can diagnose a formatting defect by reading the currency table — so the practical support risk is low as long as the fork lives somewhere the team can find it.
Scaling. Effectively a non-issue. Formatting is pure, deterministic, and CPU-trivial: no I/O, no network, no currency-rate lookups, no caching layer required. It will not be a throughput bottleneck at any plausible volume. The scaling caveat is architectural rather than performance: if formatting logic proliferates into views and is not centralized in the adapter, a future swap to ICU formatting becomes a wide, expensive change.
Failure modes. Ranked by likelihood:
money_format() — wrong separators, different negative-number rendering (-₹5.00 vs (₹5.00)), missing locale-specific conventions. Fails quietly, caught only by snapshots or user complaints..00, or amounts divided by 100 incorrectly at the boundary between storage and display.Ramp-up. Low for a competent Laravel developer — the adapter is a few methods and the API is a one-page read. Realistically half a day to be productive, one to two days to run the golden-file migration safely. The genuine onboarding cost is not the library but the context: the next engineer needs to know why an archived package is in the dependency tree. That rationale belongs in the adapter's docblock and the ADR, not in tribal memory.
TPM recommendation. Approve as a tactical, time-boxed replacement for money_format() on the PHP 8 upgrade path, scoped strictly to display formatting and fenced behind a project-owned adapter and a fork we control. Reject as a strategic money library. Verify INR grouping and PHP 8.x compatibility before committing, and attach a named owner plus a revisit date — a 2018 archived package should not become permanent by inattention.
How can I help you explore Laravel packages today?