A small, precise money helper class for arithmetic operations and comparisons with configurable decimal precision. Uses bcmath for deterministic decimal calculations.
- Namespace:
Ecommerce
- PHP: 8.1+
- Requires: PHP extension
ext-bcmath
composer require ecommerce-utilities/money
- Ensure the bcmath PHP extension is enabled (e.g.,
sudo apt-get install php-bcmath
and restart your web server/CLI). - Include the class in your project (e.g., via PSR-4 autoloading) and use the
Ecommerce
namespace.
<?php
use Ecommerce\Money;
// Create
$price = Money::fromValue(19.99); // Default: 2 decimal places
$tax = Money::fromValue(1.90, 2); // explicit precision
$zero = Money::zero(); // 0.00
// Arithmetic
$total = Money::add($price, $tax); // 21.89
$rest = Money::sub($total, 5); // 16.89
$multi = Money::mul($rest, 3); // 50.67
$share = Money::div($multi, 4); // 12.67 (with 2 decimals)
// Comparisons
$isSame = Money::isEqual(10, '10.00'); // true
$isLeftGt = Money::isLeftSideGreater(5, 7); // true (5 < 7)
$isRightGt = Money::isRightSideGreater(9.99, 9.98); // true (9.99 > 9.98)
// Access and string representation
$asFloat = $total->getValue(); // float 21.89
$dp = $total->getDecimalPrecision(); // int 2
echo (string) $total; // "21.89"
- The default precision is 2 decimal places.
- You can set precision explicitly in several places:
- When creating:
Money::fromValue(123.456, 3)
- In operations:
Money::add($a, $b, 3)
- When creating:
- During operations, precision is determined as follows:
- The provided
$decimalPrecision
parameter (if set), - otherwise, the precision of a
Money
operand (if present), - otherwise, 2.
- The provided
Examples:
<?php
use Ecommerce\Money;
$a = Money::fromValue(1.2345, 4);
$b = 2;
$sumDefault = Money::add($a, $b); // uses 4 from the Money operand -> "3.2345"
$sumForced = Money::add($a, $b, 3); // overrides -> "3.235"
All methods accept Money
, int
, float
, numeric-string
, or null
(depending on the method):
<?php
use Ecommerce\Money;
Money::add(null, 10); // 10.00
Money::add(null, null); // 0.00 (Money::zero())
Money::sub(null, 5); // 0.00
Money::mul(10, null); // 0.00
Money::div(10, 0); // 10.00 (division by 0 returns the left operand)
Notes:
fromMoney($value)
returns the numeric value (float) regardless of the input type.- The string representation is always formatted according to the set precision, e.g.,
"12.30"
.
- Define a consistent precision for a domain (e.g., currency: 2, crypto assets: 8).
- For critical calculations, pass the precision explicitly to
add/sub/mul/div
. - Use the comparison helpers instead of direct float comparisons.
- Creation:
Money::fromValue(null|Money|int|float|string $value, ?int $decimalPrecision = null): Money
Money::zero(): Money
- Arithmetic:
Money::add($a, $b, ?int $decimalPrecision = null): Money
Money::sub($a, $b, ?int $decimalPrecision = null): Money
Money::mul($a, $b, ?int $decimalPrecision = null): Money
Money::div($a, $b, ?int $decimalPrecision = null): Money
- Comparisons:
Money::isEqual($a, $b, ?int $decimalPrecision = null): bool
Money::isLeftSideGreater($a, $b, ?int $decimalPrecision = null): bool
// true when a < bMoney::isRightSideGreater($a, $b, ?int $decimalPrecision = null): bool
// true when a > b
- Access:
$money->getValue(): float
$money->getDecimalPrecision(): int
(string) $money
for formatted output
Feel free to use this class in your projects. Contributions and improvements are welcome.