1. How to count money
and not lose it
Piotr Horzycki
www.peterdev.pl | twitter.com/peterdevpl
2. var_dump((int) ('4.20' * 100));
→ int(420)
var_dump((int) ('4.10' * 100));
→ int(409)
“I can set a product price to 4.20 PLN, but not 4.10
– it’s being changed to 4.09. Why?”
Bugs...
3. if (parseInt(amount) > 0) {
/* proceed with payment */
} else {
/* disable payment button */
}
Why does 0.5 not work?
Bugs...
6. “A large proportion of the computers in this world
manipulate money, so it's always puzzled me that
money isn't actually a first class data type in any
mainstream programming language. The lack of a
type causes problems, the most obvious surrounding
currencies. (...) The more subtle problem is with
rounding. Monetary calculations are often rounded to
the smallest currency unit. When you do this it's easy to
lose pennies (or your local equivalent) because of
rounding errors.
The good thing about object-oriented programming is
that you can fix these problems by creating a Money
class that handles them. Of course, it's still surprising
that none of the mainstream base class libraries
actually do this.”
https://martinfowler.com/eaaCatalog/money.html
7. use MoneyCurrency;
use MoneyMoney;
// 5,00 USD
$fiver = new Money(500, new Currency('USD'));
// or shorter:
$fiver = Money::USD('500');
MoneyPHP: PHP implementation of the Money pattern
13. use MoneyMoney;
$profit = Money::EUR(5); // 5 euro cents
list($my_cut, $investors_cut) = $profit->allocate([70, 30]);
// $my_cut is 4 cents, $investors_cut is 1 cent
Allocating profits
14. use MoneyMoney;
$profit = Money::EUR(5); // 5 euro cents
list($my_cut, $investors_cut) = $profit->allocate([70, 30]);
// $my_cut is 4 cents, $investors_cut is 1 cent
// The order is important:
list($investors_cut, $my_cut) = $profit->allocate([30, 70]);
// $my_cut is 3 cents, $investors_cut is 2 cents
Allocating profits
21. Converting currencies with MoneyPHP
use MoneyConverter;
use MoneyCurrency;
use MoneyExchangeFixedExchange;
$exchange = new FixedExchange([
'EUR' => [
'USD' => 1.25
]
]);
$converter = new Converter(new ISOCurrencies(), $exchange);
$eur100 = Money::EUR(100);
$usd125 = $converter->convert($eur100, new Currency('USD'));
22. Converting currencies with MoneyPHP and Swap
use MoneyMoney;
use MoneyConverter;
use MoneyExchangeSwapExchange;
use SwapBuilder;
$swap = (new Builder())
->add('fixer', ['access_key' => 'your-access-key'])
->build();
$exchange = new SwapExchange($swap);
$converter = new Converter(new ISOCurrencies(), $exchange);
$eur100 = Money::EUR(100);
$usd125 = $converter->convert($eur100, new Currency('USD'));
30. $currencies = new ISOCurrencies();
$americanNumberFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$mexicanNumberFormatter = new NumberFormatter('es_MX', NumberFormatter::CURRENCY);
$dollarsFormatter = new IntlMoneyFormatter($americanNumberFormatter, $currencies);
$pesosFormatter = new IntlMoneyFormatter($mexicanNumberFormatter, $currencies);
$dollars = new Money(12345, new Currency('USD'));
$pesos = new Money(12345, new Currency('MXN'));
echo $dollarsFormatter->format($dollars) . PHP_EOL; // $123.45
echo $pesosFormatter->format($pesos); // $123.45
Be careful with parsing money strings!