Using your own currency in MoneyPHP
I have this talk about the MoneyPHP library and handling currencies in general. I often get a question: is it possible to define custom currencies in MoneyPHP? A possible use case would be loyalty cards for example, with their own scoring system.
The answer is: YES! MoneyPHP not only accepts all ISO 4217 currencies, but also allows you to define a custom list with any identifiers and any subunits. So for example, you can create a currency called BlahBlahBlah
that has 7 decimal points and then convert an amount from your currency to another by providing a custom exchange list.
In the example below, we’re creating two fictious currencies: MyPoints
and TheirPoints
. The first one has two decimal points while another has none (only whole numbers). We create a Money
object that holds exactly 123.45 MyPoints.
Then we specify an exchange table which says that 1 TheirPoint equals 0.5 MyPoints. We create a currency converter and then try to convert one currency to another. 123.45 * 0.5
equals 61.725
. But since TheirPoints subunit is 0, the amount has to be rounded up, so we get 62.
use Money\Converter;
use Money\Currencies\CurrencyList;
use Money\Currency;
use Money\Exchange\FixedExchange;
use Money\Money;
$currencyList = new CurrencyList([
'MyPoints' => 2,
'TheirPoints' => 0,
]);
$myCardAmount = new Money(12345, new Currency('MyPoints'));
$exchange = new FixedExchange([
'MyPoints' => [
'TheirPoints' => 0.5,
],
]);
$converter = new Converter($currencyList, $exchange);
$theirCardAmount = $converter->convert(
$myCardAmount, new Currency('TheirPoints')
);
echo $theirCardAmount->getAmount(); // 62
However, there can be a problem with currency formatting using PHP’s intl
library. Consider this example:
$numberFormatter = new \NumberFormatter(
'en_US', \NumberFormatter::CURRENCY
);
$moneyFormatter = new \Money\Formatter\IntlMoneyFormatter(
$numberFormatter, $currencyList
);
echo $moneyFormatter->format($theirCardAmount); // The 62.00
The odd output (The
instead of Their
and the unwanted fractional part) comes from the fact that PHP’s NumberFormatter handles only ISO currencies which have 3-character symbols. So you should use \NumberFormatter::DECIMAL
instead and add your custom symbol manualy.