leaflownet / ext-money
Immutable Money value object with 10^-8 micro precision and BcMath-backed arithmetic.
0.1.0
2026-05-24 21:03 UTC
Requires
- php: ^8.4
- ext-bcmath: *
Requires (Dev)
- pestphp/pest: ^4.0
This package is not auto-updated.
Last update: 2026-05-25 19:30:08 UTC
README
Immutable Money value object with 10⁻⁸ micro precision and BcMath-backed
arithmetic. Designed for cloud-billing accounting where per-second rates need
to multiply by per-month durations without losing precision.
Why another money library?
| Library | Precision | Approach |
|---|---|---|
moneyphp/money |
ISO 4217 minor unit (e.g. cents) | Per-currency fractionDigits, tied to ISO standard |
brick/money |
Configurable via CustomContext(N) |
Powerful but requires custom currency for non-ISO precision |
leaflownet/ext-money |
Fixed 10⁻⁸ micro | Simple int64-backed VO, BcMath overflow guards, no currency-tied scale |
If you bill by the second and need 0.00016666... CNY/sec × 2_592_000 sec to
round-trip exactly, you want micro precision. ISO minor (cent) silently
collapses to zero in this scenario.
Installation
composer require leaflownet/ext-money
Requires PHP 8.4+ (uses the BcMath\Number OOP API) and ext-bcmath.
Usage
use LeaflowNet\Money\Money; // Constructors $balance = Money::fromMicro(100_000_000, 'CNY'); // 1.00 CNY $cents = Money::fromCents(1234, 'USD'); // 12.34 USD $major = Money::fromMajor(5, 'CNY'); // 5.00 CNY $zero = Money::zero('CNY'); // 0.00 CNY // Arithmetic (all go through BcMath\Number with int64 overflow guards) $total = $balance->add(Money::fromCents(500)); // 1.05 CNY $diff = $balance->sub(Money::fromMicro(1)); // 0.99999999 CNY $rate = Money::fromMicro(1_000)->mul(2_592_000); // per-second × seconds-in-month // Rational multiplication: avoids overflow even when numerator * den exceeds int64 $prorated = $monthly->mulRational(7, 24); // 7 / 24 of monthly // Comparison $balance->compare($zero); // -1 / 0 / 1 $balance->isZero(); // false $balance->isNegative(); // false $balance->equals($zero); // false // Display (floors to cents, 10^-2) $balance->toDisplayCents(); // 100 $balance->toDisplayString(); // "1.00" // Cross-currency operations throw CurrencyMismatchException $cny = Money::fromCents(100, 'CNY'); $usd = Money::fromCents(100, 'USD'); $cny->add($usd); // throws CurrencyMismatchException
Properties
Money::$micro— signed 64-bit integer, the amount in 10⁻⁸ unitsMoney::$currency— uppercase ISO-4217-style 3-letter code
Range and overflow
Moneycan represent any value within signed int64 micro: roughly -92.2 billion to +92.2 billion of the major unit.- All arithmetic throws
InvalidArgumentException("Money overflow: ...")if the result would exceedPHP_INT_MAXor fall belowPHP_INT_MIN. - Intermediate computations use arbitrary-precision
BcMath\Number, so the guard fires before the result is cast back toint.
License
MIT — see LICENSE.