simp / price
This is php package that works with numerical values as amount of entity
Requires
None
Requires (Dev)
- phpunit/phpunit: ^13.4
- rector/rector: ^2.8
- symfony/var-dumper: ^8.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-10-29 21:39:46 UTC
README
simp/price is a PHP library for working with monetary amounts. It provides
currency metadata, currency-aware number formatting, exchange-rate conversion,
and a mutable Price object for common amount operations.
Features
- Look up currency codes, names, symbols, and associated country or region data.
- Access a built-in list of cryptocurrency metadata.
- Format amounts using currency-specific decimal and separator patterns.
- Add, subtract, multiply, divide, compare, and round price amounts.
- Convert amounts using rates from the Frankfurter API, with rates cached locally.
- Restore a
Priceobject to its original amount and currency.
Requirements
- PHP 8.5 or later. The current exchange-rate cache implementation uses PHP's
array_first()function. - The PHP cURL extension to download exchange rates when a fresh cache is not available.
Installation
Install the package with Composer:
composer require simp/price
In a project using Composer, load its autoloader:
require __DIR__ . '/vendor/autoload.php';
Quick start
Create a Price with an amount and ISO currency code. The currency defaults to
USD:
use Simp\Price\lib\Price; $price = new Price(19.99, 'USD'); echo $price->format(); // $19.99 echo $price->format(false); // 19.99 echo $price->getAmount(); // 19.99
Price operations update the same object and return it, so they can be chained:
$price ->add(5.00) ->subtract(2.50) ->multiply(2); echo $price->format(); // $44.98
Working with Price
use Simp\Price\lib\Price; $price = new Price(12.50, 'USD'); $price->getAmount(); // Current amount, as a float $price->getOriginalAmount(); // Amount passed to the constructor $price->getCurrency(); // Currency object for the current currency $price->getFormatter(); // Formatter configured for the initial currency $price->convertor(); // Exchange-rate convertor (string) $price; // Current amount without currency formatting
The arithmetic and comparison methods accept either a float or another
Price:
$price->add(2.50); $price->subtract(new Price(1.00)); $price->multiply(3); $price->divide(2); $price->isEqual(10.00); $price->isLessThan(20.00); $price->isGreaterThan(5.00); $price->isDivisibleBy(2);
divide() throws Simp\Price\Exception\DivisionByZeroException if the divisor
is zero or if the current amount is zero.
The rounding methods mutate and return the Price:
$price->roundUp(); $price->roundDown(); $price->roundEven(); $price->roundOdd();
In the current implementation, roundUp() uses ceil(), roundDown() uses
PHP's round() (nearest integer), and both roundEven() and roundOdd() use
floor(). Despite their names, the last two do not currently round to the
nearest even or odd integer.
To restore the amount and currency to their constructor values:
$price->resetToOriginal();
Currency metadata
Use Currency to look up metadata by code. Codes are matched without regard to
case:
use Simp\Price\lib\Currency; $usd = new Currency('usd'); echo $usd->getCode(); // USD echo $usd->getName(); // Currency name from the built-in data echo $usd->getSymbol(); // $ echo $usd->getCountry();
The complete selected entry and the selected currency group are also available:
$usd->getCurrency(); $usd->getCurrencyGroup();
To search the built-in cryptocurrency list, pass any group selector other than
normal:
$bitcoin = new Currency('BTC', 'crypto'); echo $bitcoin->getName(); // Bitcoin echo $bitcoin->getSymbol(); // ₿
Unsupported codes throw
Simp\Price\Exception\CurrencyNotFoundException. Currency metadata is static
data bundled with the package; it may be outdated or contain inaccuracies.
Cryptocurrency entries do not provide country data, so getCountry() is for
entries that define a country.
Number formatting
Use Formatter directly when you only need a formatted amount:
use Simp\Price\lib\Formatter; $usdFormatter = new Formatter('USD'); echo $usdFormatter->format(1234.5); // 1,234.50 $europeanFormatter = new Formatter('ARS'); echo $europeanFormatter->format(1234.5); // 1.234,50
Price::format() uses the formatter created for the initial currency and can
include the current currency symbol:
$price->format(); // Formatted amount prefixed with the currency symbol $price->format(false); // Formatted amount without the symbol
Currency conversion
Price::convert() converts the current amount to a target currency code and
updates the Price object's currency:
use Simp\Price\lib\Price; $price = new Price(100, 'USD'); $price->convert('EUR'); echo $price->getAmount(); // Converted amount echo $price->getCurrency()->getCode(); // EUR
The Convertor class can also be used directly:
use Simp\Price\lib\Convertor; $convertor = new Convertor('USD'); $rate = $convertor->getRate('EUR'); $convertedAmount = $convertor->convert(100, 'EUR'); $rateDate = $convertor->getPublishDate('EUR');
The convertor loads rates for its base currency from
src/rates/exchange-ratings.json. If the cache is missing, empty, or not from
the current date, it attempts to download rates from the configured Frankfurter
API source. This means construction may require network access and a writable
cache directory. A failed download may raise
Simp\Price\Exception\FailedExchangeRateDownloadException. A missing quote
currency raises
Simp\Price\Exception\QuoteCurrencyForExchangeNotSupportedException.
The formatter held by a Price is initialized for its original currency and
is not replaced by convert(). If you need formatting rules for the converted
currency, create a Formatter for that currency explicitly.
Exceptions
The package defines these exceptions:
Simp\Price\Exception\CurrencyNotFoundException— the requested currency could not be found in the bundled metadata.Simp\Price\Exception\FailedExchangeRateDownloadException— exchange rates could not be downloaded after retries.Simp\Price\Exception\QuoteCurrencyForExchangeNotSupportedException— no rate is available for the requested quote currency.Simp\Price\Exception\DivisionByZeroException— division was attempted with a zero divisor or a zero current amount.
Running tests
The test suite uses PHPUnit:
vendor/bin/phpunit
Conversion tests use controlled in-memory exchange rates; they do not depend on the live API.
Rector
Rector is configured in rector.php for the package source and tests, targeting
PHP 8.5 with dead-code and code-quality rules enabled. Preview proposed changes
without modifying files:
composer rector:check
Apply the configured refactorings with:
composer rector
License
This package is published under the MIT license.