Amounts & precision
A minor amount is always a canonical integer string: 0, or an optional minus followed by up to 65 significant digits (Money::MAX_DIGITS) — no plus sign, leading zeros, whitespace, dot or exponent. minor() only ever returns this grammar.
$big = Money::ofMinor('123456789012345678901234567890', 'EUR');
$big->digits(); // 30
$big->fitsInt(); // false
$big->minorInt(); // throws AmountOverflow — no silent (int) path
// Never compare raw minors in PHP: numeric strings go through float above int64
$a->minor() > $b->minor(); // unreliable for large amounts
$a->isGreaterThan($b); // always exact
Money::ofMinor('007', 'EUR')->minor(); // "7" — normalized on entry
Money::ofMinor('5.0', 'EUR'); // throws InvalidAmount — minors are integers- Never (int)-cast or PHP-compare raw minors — PHP compares numeric strings through floats above int64. Use the Money comparison methods.
- minorInt() is the only int bridge; it throws AmountOverflow outside int64, and fitsInt() tells you in advance.
- JSON carries minor as a string: a JSON number above 2⁵³ is corrupted by JavaScript.
- Integer inputs are normalized on entry ("007" → "7", "-0" → "0"); "+5", " 5", "5.0" and "5e3" throw InvalidAmount.
Limits
| Bound | Value | Exception |
|---|---|---|
| Minor digits in memory | 65 | AmountOverflow |
| Decimal input digits | 90 | InvalidAmount |
| Parser input (characters) | 128 | InvalidAmount |
| split() parts | 1..10 000 | InvalidAllocation |
| Scales (MinorUnits, ofScaled, toScaled) | 0..36 | InvalidAmount |
| Custom currency exponent | 0..18 | InvalidCurrency |
| Ratio terms after reduction (digits) | 80 | InvalidRatio |
| Persisted digits (schema.precision) | 38 | InvalidMoneyValue |
Database columns
$table->money() emits a signed decimal(P, 0) amount column (P = money.schema.precision, default 38) plus a currency column. Decimal gives native numeric ORDER BY, range filters and exact SUM — bigint would bring back the int64 ceiling, and varchar sorts “9” after “10”.
| Engine | Column | PDO returns | Out of range |
|---|---|---|---|
| PostgreSQL | numeric(38,0) | string "1050" | numeric_value_out_of_range error |
| MySQL / MariaDB | decimal(38,0) | string "1050" | Strict-mode out-of-range error (non-strict MySQL is unsupported) |
| SQLite | numeric | int 1050 | Would silently become REAL — so the cast refuses amounts beyond int64 |
The scale is always 0 — the exponent lives in the currency registry, so one column holds JPY (0), EUR (2) and ETH (18) rows. Lower money.schema.precision to 19 for int64-sized columns; Currency::maxMajorAmount() reports the largest storable major amount:
Currency::of('EUR')->maxMajorAmount(19); // "99999999999999999.99"Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.