PHPackages                             maba/monetary - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. maba/monetary

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

maba/monetary
=============

PHP library for money operations

0.10.0(6y ago)467.5k↓40.3%41MITPHPPHP &gt;=5.3.2CI failing

Since Sep 21Pushed 6y ago1 watchersCompare

[ Source](https://github.com/mariusbalcytis/monetary)[ Packagist](https://packagist.org/packages/maba/monetary)[ RSS](/packages/maba-monetary/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (7)Used By (1)

PHP Library for Operations with Money
=====================================

[](#php-library-for-operations-with-money)

Instead of storing prices, profit and any other amount of money in float or integer variable, use Money value object instead. It groups amount with currency, as amount without currency does not give much information. Furthermore, this library uses [math library](https://github.com/mariusbalcytis/math) for arbitrary precision mathematics. Thus, it uses strings for storing money units.

### Why not floats?

[](#why-not-floats)

- Floats are not reliable for making operations with money as they can loose precision and cents can get lost.

### Why not integers?

[](#why-not-integers)

- When max integer value is reached, crazy things can happen: it can be truncated or even get negative. These types of errors can be critical, especially when working with money. On 32bit systems (and any system on Windows) max int value is 2147483647. As this is enough for most cases, some currencies are relatively very small compared to others (for example, 2,147,483,647.00 BYR is about 150,000.00 EUR).
- There might be cases, where money should be calculated or even saved without rounding to smallest available units. For example, very small commissions (parts of cent), which can add to a big amount when large number of them are added.
- When storing amount as integer, you must always take into account the currency divisor (smallest available unit in that currency) before outputing the result or any other operation. For example, most currencies have cents as their smallest unit while smallest unit for Bahraini Dinar is 0.001 and Japanese Yen has no cents at all. Alternatively, if you always store units as cents, you cannot represent smallest units of some currencies.

### Architecture

[](#architecture)

`Money` is value object - it's immutable. In other words, if you need to change the amount or currency, just create another `Money` object. The same `Money` object can be referenced in several places, so changing only the fields of this object could unintentionally change money amount or currency in some other place.

Also, default implementation of `Money` holds no logic - it just contains amount and currency. All operations are performed by services:

- Arithmetic and comparison operations - by `MoneyCalculator`, which implements `MoneyCalculatorInterface`.
- Validation - by `MoneyValidator` and `FinalMoneyValidator`, which implement `MoneyValidatorInterface`. `FinalMoneyValidator` asserts that `Money` contains no smaller parts than smallest currency unit.
- Creation of `Money` objects - by `MoneyFactory`, which implements `MoneyFactoryInterface`.

#### Why not self-contained logic?

[](#why-not-self-contained-logic)

This approach lets you change the logic and the class used to represent money easily.

For example, you can use some custom `Money` class - this library makes operations on objects with `MoneyInterface`. As `MoneyFactoryInterface` is always used to create new entities, you can change result class of any `Money` operation:

```
// ...
// lots of code using MyMoney class
// ...

class MyMoney implements MoneyInterface
{
    // ...

    public function getAmount()
    {
        // ...
    }

    public function getCurrency()
    {
        // ...
    }
}

class MyMoneyFactory implements MoneyFactoryInterface
{
    // create instances of MyMoney here
}

// construct $calculator with instance of MyMoneyFactory

$result = $calculator->add(new MyMoney('1', 'EUR'), new Money('2.12', 'EUR'));  // you can mix classes, too
// $result is instance of MyMoney now
```

Another example - implementation of `MoneyCalculatorInterface`, which lets you to add `Money` objects with different currencies, automatically making currency exchange operations.

Installing
----------

[](#installing)

```
composer require maba/monetary
```

Usage
-----

[](#usage)

```
use Maba\Component\Math\BcMath;
use Maba\Component\Math\Math;
use Maba\Component\Math\NumberFormatter;
use Maba\Component\Math\NumberValidator;
use Maba\Component\Monetary\Factory\MoneyFactory;
use Maba\Component\Monetary\Formatting\FormattingContext;
use Maba\Component\Monetary\Formatting\MoneyFormatter;
use Maba\Component\Monetary\Information\MoneyInformationProvider;
use Maba\Component\Monetary\Validation\MoneyValidator;
use Maba\Component\Monetary\Money;
use Maba\Component\Monetary\MoneyCalculator;

// set up dependencies. I would really suggest to use DIC here
$math = new Math(new BcMath());
$informationProvider = new MoneyInformationProvider();
$factory = new MoneyFactory($math, new MoneyValidator($math, $informationProvider, new NumberValidator()));
$calculator = new MoneyCalculator($math, $factory, $informationProvider);

// make math operations on Money objects
$result = $calculator->ceil(
    $calculator->mul(
        $calculator->mul(
            $calculator->add(new Money('12.23', 'EUR'), new Money('32.12', 'EUR')),
            879134421.2183
        ),
        12.33
    )
);

// compare Money objects
if ($calculator->isGt($result, $factory->createZero())) {
    // format Money objects as strings
    $formatter = new MoneyFormatter(
        $calculator,
        $informationProvider,
        new NumberFormatter($math),
        array('EUR' => '€'),        // optional - symbols to replace currency codes
        '%currency%%amount%'        // optional - custom template
    );

    // set up context. $context argument is optional and needed only if defaults need to be changed
    $context = new FormattingContext();
    $context->setThousandsSeparator(' ');
    // set other formatting options in the context if needed
    echo $formatter->formatMoney($result, $context); // outputs €480 741 910 794.12
}
```

Running tests
-------------

[](#running-tests)

[![Travis status](https://camo.githubusercontent.com/c99d6a011ba6fabf8f4ab5eb4e193cd6e38fed0b6b845073830d1129fbc85a88/68747470733a2f2f7472617669732d63692e6f72672f6d617269757362616c63797469732f6d6f6e65746172792e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/mariusbalcytis/monetary)[![Coverage Status](https://camo.githubusercontent.com/442bc2c8d87bee9f2df93d95a26eb676a769365d34d852a109a913852f9c862c/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6d617269757362616c63797469732f6d6f6e65746172792f62616467652e7376673f6272616e63683d6d617374657226736572766963653d676974687562)](https://coveralls.io/github/mariusbalcytis/monetary?branch=master)

```
composer install
vendor/bin/phpunit

```

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity35

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~401 days

Recently: every ~502 days

Total

6

Last Release

2250d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6e131c9aa5f5a4fc3cc2f5e01b377ef33bbc3468acc95ff890fc6e8353d9cf67?d=identicon)[mariusbalcytis](/maintainers/mariusbalcytis)

---

Top Contributors

[![mariusbalcytis](https://avatars.githubusercontent.com/u/1590072?v=4)](https://github.com/mariusbalcytis "mariusbalcytis (6 commits)")[![ivelinahristova](https://avatars.githubusercontent.com/u/3619021?v=4)](https://github.com/ivelinahristova "ivelinahristova (1 commits)")[![tomas7777](https://avatars.githubusercontent.com/u/9091359?v=4)](https://github.com/tomas7777 "tomas7777 (1 commits)")

---

Tags

currencymonetarymoneyphpmoneycurrencymonetarymoney calculationsmoney operations

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/maba-monetary/health.svg)

```
[![Health](https://phpackages.com/badges/maba-monetary/health.svg)](https://phpackages.com/packages/maba-monetary)
```

###  Alternatives

[brick/money

Money and currency library

1.9k37.9M102](/packages/brick-money)[florianv/swap

Exchange rates library for PHP

1.3k6.4M16](/packages/florianv-swap)[cknow/laravel-money

Laravel Money

1.0k4.3M22](/packages/cknow-laravel-money)[akaunting/laravel-money

Currency formatting and conversion package for Laravel

7825.3M18](/packages/akaunting-laravel-money)[kwn/number-to-words

Multi language standalone PHP number to words converter. Fully tested, open for extensions and new languages.

4235.0M21](/packages/kwn-number-to-words)[florianv/laravel-swap

Currency exchange rates library for Laravel and Lumen

3342.0M2](/packages/florianv-laravel-swap)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
