Writings
Blog
Money Object Pattern
02.04.18Money Objekte
Ich bin ein großer Verfechter des Money Objekt Pattern. Besonders in PHP bzw. dem LAMP Stack ist dieses Pattern Gold Wert und hat schon viele Probleme verhindert. Ich werde kurz die Vorzüge des Money Objekt Pattern erklären.
Es gibt 2 fundamentale Aufgabe eines Money Objektes.
- Korrektes rechnen mit Währungen
- Verbinden von Wert und Währung zu einem Typen.
3.0 > 3.0
In diesem kurzen PHP Code Abschnitt beweise ich, dass 3.0 nicht gleich 3.0 ist.
$a = 0.1; $b = 0.2; $c = $a + $b; $three = $c * 10; var_dump($three); // 3.0 var_dump($three > 3.0); // true var_dump($three == 3.0); // false
Online Demo Hier
$a = '0.1'; $b = '0.2'; $c = bcadd($a, $b, 1); $three = (float)bcmul($c, '10'); var_dump($three); // 3.0 var_dump($three > 3.0); // false var_dump($three == 3.0); // true echo PHP_EOL; $a = 0.1; $b = 0.2; $c = $a + $b; $three = $c * 10; var_dump($three); // 3.0 var_dump($three > 3.0); // true var_dump($three == 3.0); // false
Online Demo Hier
Dies ist natürlich einfach durch Gleitkommazahl Ungenauigkeit zu erklären.
Siehe hierzu auch Wikipedia
Wird PHP Money genutzt, kann bei der Berechnung zwischen verschiedenen Calculator Klassen gewählt werden.
- BcMathCalculator
- GmpCalculator
- PhpCalculator
Jede dieser Calculator Klassen schützt den Entwickler vor Gleitkommazahl Problemen bei der Arbeit mit Währungen.
1 EUR + 1USD = Exception
PHP Money kann auch Probleme mit Währungen vermieden.
/** * Returns a new Money object that represents * the sum of this and an other Money object. * * @param Money[] $addends * * @return Money */ public function add(Money ...$addends) { $amount = $this->amount; $calculator = $this->getCalculator(); foreach ($addends as $addend) { $this->assertSameCurrency($addend); $amount = $calculator->add($amount, $addend->amount); } return new self($amount, $this->currency); } /** * Asserts that a Money has the same currency as this. * * @param Money $other * * @throws \InvalidArgumentException If $other has a different currency */ private function assertSameCurrency(Money $other) { if (!$this->isSameCurrency($other)) { throw new \InvalidArgumentException('Currencies must be identical'); } }
Bei einer Addition von 1EUR + 1USD wird das Money Objekt eine Exception werfen. Somit ist es nicht mehr möglich versehentlich Äpfel mit Birnen zu vergleichen.
Links