Codexportfolio intelligence

@philiprehberger/php-money

Immutable Money value object with currency support, formatting, arithmetic, and Laravel Eloquent cast

PHPPackagist

Capabilities

README

PHP Money

Tests Latest Version on Packagist Last updated

Immutable Money value object with currency support, formatting, arithmetic, and Laravel Eloquent cast.

Requirements

  • PHP 8.2+
  • ext-intl (for format())
  • Laravel 11 or 12 (optional, only for MoneyCast)

Installation

composer require philiprehberger/php-money

Laravel

The package auto-discovers MoneyServiceProvider. No configuration is required.

Usage

Creating Money

use PhilipRehberger\Money\Money;

// Static currency factories — amount in smallest unit (cents)
$price   = Money::USD(1999);   // $19.99
$tax     = Money::EUR(1500);   // €15.00
$pence   = Money::GBP(999);    // £9.99

// Generic factory
$amount  = Money::of(500, 'CAD');  // CA$5.00

// Zero value
$nothing = Money::zero('USD');

// Parse a formatted string
$parsed  = Money::parse('$29.99', 'USD');  // Money::USD(2999)
$parsed2 = Money::parse('€1,299.00', 'EUR'); // Money::EUR(129900)

Arithmetic

All arithmetic methods return new Money instances and leave the original unchanged.

$subtotal = Money::USD(1000);
$tax      = Money::USD(80);
$discount = Money::USD(150);

$total = $subtotal->add($tax)->subtract($discount);
$total->getAmount(); // 930 (= $9.30)

Comparison

$a = Money::USD(1000);
$b = Money::USD(2000);

$a->equals($b);             // false
$a->lessThan($b);           // true
$a->isZero();               // false
$a->isPositive();           // true
$a->isNegative();           // false

Allocation

// Split $10.00 three ways by ratio
$parts = Money::USD(1000)->allocate([1, 1, 1]);
// [334, 333, 333] — totals exactly 1000

// Split equally (shorthand)
$parts = Money::USD(1000)->allocateEqual(3);
// [334, 333, 333]

Collection Operations

$a = Money::USD(1000);
$b = Money::USD(2000);
$c = Money::USD(3000);

Money::sum($a, $b, $c)->getAmount();     // 6000
Money::avg($a, $b, $c)->getAmount();     // 2000
Money::minimum($a, $b, $c)->getAmount(); // 1000
Money::maximum($a, $b, $c)->getAmount(); // 3000

Rounding Modes

use PhilipRehberger\Money\RoundingMode;

$price = Money::USD(1000);

$price->multiply(1.005);                            // 1005 (HALF_UP default)
$price->multiply(1.005, RoundingMode::HALF_DOWN);   // 1005
$price->multiply(1.005, RoundingMode::FLOOR);       // 1005
$price->multiply(1.005, RoundingMode::CEILING);     // 1005

Currency Conversion

$usd = Money::USD(10000); // $100.00
$eur = $usd->convertTo(Currency::EUR(), 0.85); // €85.00

Min / Max

$a = Money::USD(500);
$b = Money::USD(200);
$c = Money::USD(800);

Money::min($a, $b, $c)->getAmount(); // 200
Money::max($a, $b, $c)->getAmount(); // 800

Formatting

$price = Money::USD(1234567);

$price->format('en_US');  // "$12,345.67"
$price->format('de_DE');  // "12.345,67 $"
$price->format('fr_FR');  // "12 345,67 $US"

Laravel Eloquent Cast

use PhilipRehberger\Money\Laravel\MoneyCast;

class Product extends Model
{
    protected $casts = [
        'price' => MoneyCast::class,
    ];
}

$product->price = Money::USD(2999);
$product->save();
// Stored as: {"amount":2999,"currency":"USD"}

API

Money

MethodDescriptionReturns
Money::USD(int $amount)Create USD instance (and other static currency factories)Money
Money::of(int $amount, string $currency)Create instance for any currency codeMoney
Money::zero(string $currency)Create zero-value instanceMoney
Money::parse(string $value, string $currency)Parse a formatted stringMoney
Money::sum(Money $first, Money ...$rest)Sum all money valuesMoney
Money::avg(Money $first, Money ...$rest)Average of all money valuesMoney
Money::minimum(Money $first, Money ...$rest)Return the smallest valueMoney
Money::maximum(Money $first, Money ...$rest)Return the largest valueMoney
Money::min(Money ...$amounts)Return the smallest valueMoney
Money::max(Money ...$amounts)Return the largest valueMoney
->getAmount()Get amount in smallest unitint
->getCurrency()Get Currency instanceCurrency
->add(Money $other)Add two money valuesMoney
->subtract(Money $other)Subtract two money valuesMoney
->multiply(int|float $factor, ?RoundingMode $mode)Multiply by a factorMoney
->divide(int|float $divisor, ?RoundingMode $mode)Divide by a divisorMoney
->percentage(int|float $percent)Calculate a percentageMoney
->convertTo(Currency $target, float $rate)Convert to another currencyMoney
->allocate(int[] $ratios)Split proportionally without rounding lossMoney[]
->allocateEqual(int $parts)Split equally (remainder to first parts)Money[]
->equals(Money $other)Check equalitybool
->greaterThan(Money $other)Greater than comparisonbool
->lessThan(Money $other)Less than comparisonbool
->greaterThanOrEqual(Money $other)Greater than or equal comparisonbool
->lessThanOrEqual(Money $other)Less than or equal comparisonbool
->isZero()Check if amount is zerobool
->isPositive()Check if amount is positivebool
->isNegative()Check if amount is negativebool
->format(string $locale = 'en_US')Locale-aware formatted stringstring
->toArray()Serialise to arrayarray

RoundingMode

CaseValueDescription
HALF_UPhalf_upRound half away from zero (default)
HALF_DOWNhalf_downRound half toward zero
HALF_EVENhalf_evenBanker's rounding
CEILINGceilingRound toward positive infinity
FLOORfloorRound toward negative infinity

Exceptions

ExceptionWhen thrown
CurrencyMismatchExceptionArithmetic or comparison between different currencies
InvalidAmountExceptionDivision by zero, unparseable string, empty/negative ratios
InvalidArgumentExceptionUnknown currency code, empty currency code, invalid cast input

Development

composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT