Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
M

money

> 编程语言
Open source

A money and currency library for PHP

1.9K stars0 likes2 views
WebsiteGitHub

About

A money and currency library for PHP

Brick\Money

A money and currency library for PHP.

Introduction

This library provides immutable classes to work with monies and currencies, with exact arithmetic and explicit control over rounding — avoiding the silent rounding errors inherent to floating-point.

It is based on brick/math and handles exact calculations on monies of any size.

Installation

This library is installable via Composer:

bash
composer require brick/money

Requirements

This library requires PHP 8.2 or later.

For PHP 8.1 compatibility, you can use version 0.10. For PHP 8.0, you can use version 0.8. For PHP 7.4, you can use version 0.7. For PHP 7.1, 7.2 & 7.3, you can use version 0.5. Note that these PHP versions are EOL and not supported anymore. If you're still using one of these PHP versions, you should consider upgrading as soon as possible.

Although not required, it is recommended that you install the GMP or BCMath extension to speed up calculations.

Project status & release process

While this library is still under development, it is well tested and should be stable enough to use in production environments.

The current releases are numbered 0.x.y. When a non-breaking change is introduced (adding new methods, optimizing existing code, etc.), y is incremented.

When a breaking change is introduced, a new 0.x version cycle is always started.

It is therefore safe to lock your project to a given release cycle, such as 0.15.*.

If you need to upgrade to a newer release cycle, check the release history for a list of changes introduced by each further 0.x.0 version.

Currency updates

This library is based on the latest ISO 4217 standard. This is a living standard, so updates to currencies are expected to happen regularly.

Updates to the following features will be considered breaking changes, and will only be released in a new major version after 1.0:

  • Currencies obtained by alpha currency code such as EUR or USD, through Currency::of(), Money::of(), Money::ofMinor(), IsoCurrencyProvider::getCurrency(), etc.

The following features are evolving constantly, they will not be considered breaking changes and may be updated in minor releases after 1.0:

  • Currencies obtained by numeric currency code such as 978 or 840, through Currency::ofNumericCode(), IsoCurrencyProvider::getCurrencyByNumericCode(), etc.
  • Current currencies obtained by country code such as FR or US, through Currency::ofCountry(), IsoCurrencyProvider::getCurrencyForCountry(), IsoCurrencyProvider::getCurrenciesForCountry(), etc.
  • Historical currencies obtained by country code through IsoCurrencyProvider::getHistoricalCurrenciesForCountry().

Creating a Money

From a regular currency value

To create a Money, call the of() factory method:

php
use Brick\Money\Money;

$money = Money::of(50, 'USD'); // USD 50.00
$money = Money::of('19.9', 'USD'); // USD 19.90

If the given amount does not fit in the currency's default number of decimal places (2 for USD), you can pass a RoundingMode:

php
$money = Money::of('123.456', 'USD'); // RoundingNecessaryException
$money = Money::of('123.456', 'USD', roundingMode: RoundingMode::Up); // USD 123.46

Note that the rounding mode is only used once, for the value provided in of(); it is not stored in the Money object, and any subsequent operation will still need to be passed a RoundingMode when necessary.

From minor units (cents)

Alternatively, you can create a Money from a number of "minor units" (cents), using the ofMinor() method:

php
use Brick\Money\Money;

$money = Money::ofMinor(1234, 'USD'); // USD 12.34

Basic operations

Money is an immutable class: its value never changes, so it can be safely passed around. All operations on a Money therefore return a new instance:

php
use Brick\Money\Money;

$money = Money::of(50, 'USD');

echo $money->plus('4.99'); // USD 54.99
echo $money->minus(1); // USD 49.00
echo $money->multipliedBy('1.999'); // USD 99.95
echo $money->dividedBy(4); // USD 12.50

You can add and subtract Money instances as well:

php
use Brick\Money\Money;

$cost = Money::of(25, 'USD');
$shipping = Money::of('4.99', 'USD');
$discount = Money::of('2.50', 'USD');

echo $cost->plus($shipping)->minus($discount); // USD 27.49

If the two Money instances are not of the same currency, an exception is thrown:

php
use Brick\Money\Money;

$a = Money::of(1, 'USD');
$b = Money::of(1, 'EUR');

$a->plus($b); // CurrencyMismatchException

If the result needs rounding, a rounding mode must be passed as second parameter, or an exception is thrown:

php
use Brick\Money\Money;
use Brick\Math\RoundingMode;

$money = Money::of(50, 'USD');

$money->plus('0.999'); // RoundingNecessaryException
$money->plus('0.999', RoundingMode::Down); // USD 50.99

$money->minus('0.999'); // RoundingNecessaryException
$money->minus('0.999', RoundingMode::Up); // USD 49.01

$money->multipliedBy('1.2345'); // RoundingNecessaryException
$money->multipliedBy('1.2345', RoundingMode::Down); // USD 61.72

$money->dividedBy(3); // RoundingNecessaryException
$money->dividedBy(3, RoundingMode::Up); // USD 16.67

Comparing monies

You can compare two Money instances using the following methods:

  • compareTo() (returns -1|0|1)
  • isEqualTo()
  • isGreaterThan()
  • isGreaterThanOrEqualTo()
  • isLessThan()
  • isLessThanOrEqualTo()

These methods accept either a number or a Money instance. If the argument is a Money instance, it must be of the same currency as the Money instance on which the method is called, or an exception is thrown.

If you need to compare amount & currency without throwing on currency mismatch, you can use isSameValueAs() instead of isEqualTo():

php
$oneEuro = Money::of(1, 'EUR');

$oneEuro->isEqualTo(Money::of(1, 'EUR')); // true
$oneEuro->isEqualTo(Money::of(2, 'EUR')); // false
$oneEuro->isEqualTo(Money::of(1, 'USD')); // CurrencyMismatchException

$oneEuro->isSameValueAs(Money::of(1, 'EUR')); // true
$oneEuro->isSameValueAs(Money::of(2, 'EUR')); // false
$oneEuro->isSameValueAs(Money::of(1, 'USD')); // false

Comparison methods on Money instances only compare monies of the same currency. To compare monies in different currencies using exchange rates, see Comparing monies across currencies.

Checking the sign

You can inspect the sign of a Money instance using the following methods:

  • getSign() (returns -1|0|1)
  • isZero()
  • isPositive()
  • isPositiveOrZero()
  • isNegative()
  • isNegativeOrZero()

Money contexts

By default, monies have the official scale for the currency, as defined by the ISO 4217 standard (for example, EUR and USD have 2 decimal places, while JPY has 0) and increment by steps of 1 minor unit (cent); they internally use what is called the DefaultContext. You can change this behaviour by providing a Context instance. All operations on Money return another Money with the same context. Each context targets a particular use case:

Cash rounding

Some currencies do not allow the same increments for cash and cashless payments. For example, CHF (Swiss Franc) has 2 fraction digits and allows increments of 0.01 CHF, but Switzerland does not have coins of less than 5 cents, or 0.05 CHF.

You can deal with such monies using CashContext:

php
use Brick\Money\Money;
use Brick\Money\Context\CashContext;
use Brick\Math\RoundingMode;

$money = Money::of(10, 'CHF', new CashContext(step: 5)); // CHF 10.00
$money->dividedBy(3, RoundingMode::Down); // CHF 3.30
$money->dividedBy(3, RoundingMode::Up); // CHF 3.35

Custom scale

You can use custom scale monies by providing a CustomContext:

php
use Brick\Money\Money;
use Brick\Money\Context\CustomContext;
use Brick\Math\RoundingMode;

$money = Money::of(10, 'USD', new CustomContext(scale: 4)); // USD 10.0000
$money->dividedBy(7, RoundingMode::Up); // USD 1.4286

Auto scale

If you need monies that adjust their scale to fit the operation result, then AutoContext is for you:

php
use Brick\Money\Money;
use Brick\Money\Context\AutoContext;

$money = Money::of('1.10', 'USD', new AutoContext()); // USD 1.1
$money->multipliedBy('2.5'); // USD 2.75
$money->dividedBy(8); // USD 0.1375

Note that it is not advised to use AutoContext to represent an intermediate calculation result: in particular, it cannot represent the result of all divisions, as some of them may lead to an infinite repeating decimal, which would throw an exception. For these use cases, RationalMoney is what you need. Head on to the next section!

Advanced calculations

You may occasionally need to chain several operations on a Money, and only apply a rounding mode on the very last step; if you applied a rounding mode on every single operation, you might end up with a different result. This is where RationalMoney comes into play. This class internally stores the amount as a rational number (a fraction). You can create a RationalMoney from a Money, and conversely:

php
use Brick\Money\Money;
use Brick\Math\RoundingMode;

$money = Money::of('9.5', 'EUR');                       // EUR 9.50 (Money)
$money = $money->toRational()                           // EUR 19/2 (RationalMoney)
  ->dividedBy(3)                                        // EUR 19/6 (RationalMoney)
  ->plus('17.795')                                      // EUR 12577/600 (RationalMoney)
  ->multipliedBy('1.196')                               // EUR 3760523/150000 (RationalMoney)
  ->toContext($money->getContext(), RoundingMode::Down) // EUR 25.07 (Money)

The intermediate results are represented as fractions, and no rounding is ever performed. The final toContext() method converts it to a Money, applying a context and a rounding mode. Most of the time you want the result in the same context as the original Money, which is what the example above does. But you can really apply any context:

php
...
  ->toContext(new CustomContext(scale: 8), RoundingMode::Up); // EUR 25.07015334

Money allocation

Splitting

You can easily split a Money into a number of parts:

php
use Brick\Money\Money;
use Brick\Money\SplitMode;

$money = Money::of(100, 'USD');
[$a, $b, $c] = $money->split(3, SplitMode::ToFirst); // USD 33.34, USD 33.33, USD 33.33

With SplitMode::ToFirst, the remainder is distributed one step at a time to the first parts. You can also use SplitMode::Separate to get the remainder as a separate last element:

php
$money->split(3, SplitMode::Separate); // [USD 33.33, USD 33.33, USD 33.33, USD 0.01]

Allocating

You can also allocate a Money according to a list of ratios. Say you want to distribute a profit of 987.65 CHF to 3 shareholders, having shares of 48%, 41% and 11% of a company:

php
use Brick\Money\Money;
use Brick\Money\AllocationMode;

$profit = Money::of('987.65', 'CHF');

// CHF 474.08, CHF 404.93, CHF 108.64
[$a, $b, $c] = $profit->allocate([48, 41, 11], AllocationMode::FloorToFirst);

It plays well with cash roundings, too:

php
use Brick\Money\Money;
use Brick\Money\AllocationMode;
use Brick\Money\Context\CashContext;

$profit = Money::of('987.65', 'CHF', new CashContext(step: 5));

// CHF 474.10, CHF 404.95, CHF 108.60
[$a, $b, $c] = $profit->allocate([48, 41, 11], AllocationMode::FloorToFirst);

[!TIP] Ratios can be any type of number (integer, decimal, rational) and do not need to add up to 100.

Several allocation modes are available. For example, given 1.00 USD allocated by [2, 3, 1]:

|

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

PHPcurrencycurrency-converterexchange-ratesmoney

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言