SlideShare una empresa de Scribd logo
1 de 36
Descargar para leer sin conexión
How to count money
and not lose it
Piotr Horzycki
www.peterdev.pl | twitter.com/peterdevpl
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...
if (parseInt(amount) > 0) {
/* proceed with payment */
} else {
/* disable payment button */
}
Why does 0.5 not work?
Bugs...
<p>Price: <?php echo strtr($price, '.', ','); ?> PLN</p>
<p>Price: <?php echo str_replace($price, '.', ','); ?> PLN</p>
<p>Price: <?php echo number_format($price, 2, ',', ' '); ?> PLN</p>
Formatting price strings – the wrong way...
“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
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
final class Money implements JsonSerializable
{
/** @var string */
private $amount;
/** @var Currency */
private $currency;
/** @var Calculator */
private static $calculator;
private static $calculators = [
BcMathCalculator::class,
GmpCalculator::class,
PhpCalculator::class,
];
/* … */
}
$value1 = Money::EUR(800);
$value2 = Money::EUR(500);
$value3 = Money::EUR(100);
$value1->add($value2);
$value1->subtract($value2, $value3);
$value1->multiply(2);
$value1->divide(2);
$value1->mod($value2); // 3.00 EUR
$value1->ratioOf($value2); // '1.6'
Basic money arithmetics
$value1 = Money::USD(800); // $8.00
$value2 = Money::USD(100); // $1.00
$result = $value1->isSameCurrency($value2); // true
$result = $value1->equals($value2); // false
$result = $value1->greaterThan($value2); // true
Comparing money objects
Immutability
$jimPrice = $hannahPrice = Money::EUR(2500);
$coupon = Money::EUR(500);
// wrong
$jimPrice->subtract($coupon);
$jimPrice->equals($hannahPrice); // true
Immutability
$jimPrice = $hannahPrice = Money::EUR(2500);
$coupon = Money::EUR(500);
// wrong
$jimPrice->subtract($coupon);
$jimPrice->equals($hannahPrice); // true
// correct
$jimPrice = $jimPrice->subtract($coupon);
$jimPrice->lessThan($hannahPrice); // true
$jimPrice->equals(Money::EUR(2000)); // true
$jimPrice and $hannahPrice are immutable value objects
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
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
Database
INT, BIGINT…
VARCHAR...
DECIMAL (MySQL)
NUMERIC (Oracle)
FLOAT, DOUBLE...
Database
INT, BIGINT…
VARCHAR...
DECIMAL (MySQL)
NUMERIC (Oracle)
FLOAT, DOUBLE...
DECIMAL(10, 2)
total decimal
digits places
max 99,999,999.99
Exchange rates...
https://www.bankofengland.co.uk/boeapps/database/Rates.asp
https://en.wikipedia.org/wiki/Redenomination
https://www.theguardian.com/world/2018/aug/20/venezuela-bolivars-hyperinflation-banknotes
https://www.amusingplanet.com/2018/08/hungarys-hyperinflation-worst-case-of.html
Hungary’s hyperinflation in 1946
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'));
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'));
Save the conversion rate!
<p>Price: <?php echo strtr($price, '.', ','); ?> PLN</p>
<p>Price: <?php echo str_replace($price, '.', ','); ?> PLN</p>
<p>Price: <?php echo number_format($price, 2, ',', ' '); ?> PLN</p>
Price formatting again...
$100
€100
£100
¥100
...
Price formatting again...
$100
€100
£100
¥100
...
100 zł
Price formatting again...
$money = new Money(100, new Currency('USD'));
$currencies = new ISOCurrencies();
$numberFormatter = new NumberFormatter(
'en_US', NumberFormatter::CURRENCY
);
$moneyFormatter = new IntlMoneyFormatter(
$numberFormatter, $currencies
);
echo $moneyFormatter->format($money); // outputs $1.00
$money = new Money('12345678', new Currency('PLN'));
$currencies = new ISOCurrencies();
$numberFormatter = new NumberFormatter(
'pl_PL', NumberFormatter::CURRENCY
);
$moneyFormatter = new IntlMoneyFormatter(
$numberFormatter, $currencies
);
echo $moneyFormatter->format($money); // outputs 123 456,78 zł
https://en.wikipedia.org/wiki/Dollar_sign
$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!
Rounding
●
https://en.wikipedia.org/wiki/Cash_rounding
(aka Swedish rounding)
●
Polish income tax: round to the nearest whole zloty
Rounding
$money = new Money('12345', new Currency('USD'));
// $123.45 is the initial amount
$multiplied = $money->multiply('1.23', Money::ROUND_UP);
// $151.8435 before rounding
echo $dollarsFormatter->format($multiplied);
// output: $151.85
Architecture
final class Invoice
{
private $seller;
private $buyer;
private $issueDate;
private $dueDate;
/* … */
public addItem(Money $unitPrice, int $quantity, Tax $tax) {}
public getTotalAmount(): Money {}
public getTaxAmount(): Money {}
}
Architecture
interface InvoiceBuilder
{
fromSeller(Contractor $seller): self;
toBuyer(Contractor $buyer): self;
addItem(Money $unitPrice, int $quantity, Tax $tax): self;
/* … */
build(): Invoice;
}
Further reading
●
https://www.h-schmidt.net/FloatConverter/IEEE754.html
●
https://martinfowler.com/eaaCatalog/money.html
●
http://moneyphp.org/en/stable/
●
https://romaricdrigon.github.io/2019/07/05/value-objects-doctrine-and-symfony-forms
●
https://github.com/Sylius/SyliusMoneyBundle
Thank you!
Piotr Horzycki
www.peterdev.pl | twitter.com/peterdevpl

Más contenido relacionado

Similar a How to count money using PHP and not lose money

Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
brian d foy
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Masahiro Nagano
 
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכיריםמ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
Miriam Schwab
 
Php tutorial handout
Php tutorial handoutPhp tutorial handout
Php tutorial handout
SBalan Balan
 
Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP Extension
Adam Trachtenberg
 

Similar a How to count money using PHP and not lose money (20)

Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
distill
distilldistill
distill
 
logic321
logic321logic321
logic321
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of Transduction
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Advanced modulinos
Advanced modulinosAdvanced modulinos
Advanced modulinos
 
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
Designing Opeation Oriented Web Applications / YAPC::Asia Tokyo 2011
 
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכיריםמ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
מ-antispambot ועד zeroise – עשר פונקציות וורדפרס שאתם כנראה לא מכירים
 
WordPress: From Antispambot to Zeroize
WordPress: From Antispambot to ZeroizeWordPress: From Antispambot to Zeroize
WordPress: From Antispambot to Zeroize
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
[PL] Jak nie zostać "programistą" PHP?
[PL] Jak nie zostać "programistą" PHP?[PL] Jak nie zostać "programistą" PHP?
[PL] Jak nie zostać "programistą" PHP?
 
Blog Hacks 2011
Blog Hacks 2011Blog Hacks 2011
Blog Hacks 2011
 
Php tutorial handout
Php tutorial handoutPhp tutorial handout
Php tutorial handout
 
Dirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP ExtensionDirty Secrets of the PHP SOAP Extension
Dirty Secrets of the PHP SOAP Extension
 
Functional Pe(a)rls version 2
Functional Pe(a)rls version 2Functional Pe(a)rls version 2
Functional Pe(a)rls version 2
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Get into the FLOW with Extbase
Get into the FLOW with ExtbaseGet into the FLOW with Extbase
Get into the FLOW with Extbase
 

Más de Piotr Horzycki

Más de Piotr Horzycki (9)

Serial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy APISerial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy API
 
Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karierę
 
Architecture tests: Setting a common standard
Architecture tests: Setting a common standardArchitecture tests: Setting a common standard
Architecture tests: Setting a common standard
 
Software development myths that block your career
Software development myths that block your careerSoftware development myths that block your career
Software development myths that block your career
 
Software Composition Analysis in PHP
Software Composition Analysis in PHP Software Composition Analysis in PHP
Software Composition Analysis in PHP
 
How to count money with Java and not lose it
How to count money with Java and not lose itHow to count money with Java and not lose it
How to count money with Java and not lose it
 
New kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingNew kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboarding
 
Time-driven applications
Time-driven applicationsTime-driven applications
Time-driven applications
 
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPJak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
 

Último

AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 

Último (20)

%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 

How to count money using PHP and not lose money