© Muberra Turan Pehlivan/Shutterstock.com
Häufige Fehler bei Finanztransaktionen vermeiden

MoneyPHP: Internationale Transaktionen leicht gemacht


Ein Softwarefehler bei der Risikoberechnung verursachte 217 Millionen Dollar an Investorenverlusten [1]. Es handelte sich um einen Fehler in grundlegenden Dezimaloperationen, die von einem Softwareentwickler programmiert wurden. Das zeigt uns, wie wichtig und verantwortungsvoll die Arbeit eines Entwicklers ist. Sind Sie sicher, dass Sie wissen, wie Sie solche Fehler in Ihren eigenen PHP-Anwendungen vermeiden können?

Ich arbeite bereits seit 12 Jahren in der Softwareentwicklungsbranche und bei jedem Projekt, in das ich involviert war, ging es um die Verarbeitung von Finanztransaktionen. Ob es sich um einen Webshop, ein Nachrichtenportal, eine Affiliate-Marketing-Plattform oder ein internationales Zahlungsportal gehandelt hat – jedes Projekt hat einige monetäre Berechnungen durchgeführt. Es ist offensichtlich eine verantwortungsvolle Arbeit, und doch kommt es immer wieder vor, dass das Rad auf falsche Weise neu erfunden werden soll. Ist die richtige Verarbeitung von Finanztransaktionen so schwierig? Gibt es zuverlässige und verifizierte Lösungen, die wir wählen können? Wir werden uns weiter in dieses Thema vertiefen, indem wir einen sehr grundlegenden Schritt ausführen – die Erstellung einer Quittung für einen Kunden.

Geld in aller Welt

Bei über 200 Währungen auf der Welt gibt es viele Stolpersteine, die bei der Entwicklung einer Finanz-App beachtet werden müssen. Selbst wenn nur eine Währung verwendet werden soll, steckt der Teufel oftmals im Detail. Besonders schwierig wird es, wenn man sich an internationale Märkte heranwagen will. Fangen wir von vorne an. Wie schreibt und liest man Geldbeträge? Die meisten Währungen haben Untereinheiten, z. B. entspricht 1 Euro 100 Cent, daher ist es praktisch, Dezimalbrüche zu verwenden. Das Beispiel von 1 Euro und 23 Cent kann so etwa mit 1,23 EUR oder 1,23 € ausgedrückt werden.

Ein Cent lässt sich nicht halbieren, sodass von Zeit zu Zeit Rundungen vorgenommen werden müssen. Sollen zu 1,23 € 19 Prozent Steuern hinzugerechnet werden, ist das Ergebnis zunächst 1,4637 – nun muss entschieden werden, wie damit weiter verfahren werden soll. Auf- oder abrunden? Je nach örtlichem Gesetz könnten Sie am Ende entweder 1,46 oder 1,47 erhalten. Diese Unklarheit ist das Erste, was mit Product Ownern, Branchenexperten oder Anwälten geklärt werden muss. Diese Gespräche sollten niemals allein geführt werden – Ihre Aufgabe ist es, geschäftliche Anforderungen umzusetzen, nicht sie zu erraten!

Interessant wird es, wenn man verschiedene Währungen verarbeiten muss. Dann muss nicht nur Euro von Dollar unterschieden werden – es geht auch um die korrekte Umrechnung. Genauso wie Kilogramm und Pfund nicht direkt addieren werden können, können Euro und Dollar nicht zusammengezählt werden, ohne den Wechselkurs zwischen diesen beiden Währungen zu kennen. Die Kurse sind sicherlich jederzeit irgendwo im Internet zu finden, sie müssen jedoch von einer vertrauenswürdigen Quelle stammen, um die richtigen Berechnungen anstellen zu können.

Wie können die angesprochenen Probleme nun möglichst elegant gelöst werden, ohne dafür jedes Mal das Rad neu erfinden zu müssen? Wenn Millionen von Entwicklern auf der ganzen Welt mit ähnlichen Problemen zu kämpfen haben, kann davon ausgegangen werden, dass es einige gebrauchsfertige Lösungen gibt.

Warum Sie nicht alles selbst entwickeln sollten

Auf den ersten Blick sieht die Berechnung einer Quittung einfach aus: Man muss nur ein paar Zahlen addieren, richtig? Aber wie kann garantiert werden, dass die Berechnungen korrekt sind? Leider machen es uns die Computer nicht so einfach. Die CPUs wissen nicht, was eine Dezimalzahl ist. Wenn Sie einer Variablen eine Zahl wie 1,23 zuweisen, gibt es keine Garantie, dass eine CPU genau diesen Wert beibehält. Das liegt daran, dass CPUs und Programmiersprachen den IEEE-754-Standard verwenden, um Zahlen als Brüche zu speichern. Es sind reelle Zahlen, und der Datentyp heißt Floating Point [2] (oder kurz Float). Als der IEEE-Standard in den 1980er Jahren geschaffen wurde, verfügten Computer nur über sehr begrenzte Rechenleistung und Speicher. Die Ingenieure wollten einen möglichst großen Bereich von reellen Zahlen in nur 32 Bit unterbringen. Aus diesem Grund entschieden sie sich dafür, einen binären Typ statt eines Dezimaltyps zu verwenden. Jede Float Number wird als 2 ^ Exponent x Mantisse dargestellt. Wird dieser Wert in eine Dezimalzahl umgewandelt, ergibt sich sehr wahrscheinlich ein Präzisionsfehler.

Solche kleinen Fehler sind für wissenschaftliche Berechnungen in Ordnung, aber für die Finanzwelt völlig inakzeptabel. Leider ist die einzige Möglichkeit, mit PHP präzise Dezimalrechnungen durchzuführen, die Verwendung einer Bibliothek wie BC Math oder PHP Decimal. Sie ist nicht in die Sprache selbst integriert. Ein weiteres Problem, insbesondere für internationale Webanwendungen, ist die Unterscheidung von Währungen. Wenn eine Reihe von Zahlen verwechselt wird, ohne eine Idee von deren Währungen zu haben, werden die Berechnungen grundlegend falsch sein. Wenn die Prinzipien der objektorientierten Programmierung angewendet werden, sollte es ziemlich einfach sein, eine dedizierte Datenstruktur für Währungen und Finanzen zu erstellen.

Das Money-Pattern

In seinem Buch von 2002 schlug Martin Fowler eine Money-Struktur [3] vor, um einen Geldbetrag mit einer Währung zu kombinieren. Mit OOP können Sie diesen Wert in einem Objekt zusammenfassen und so sicherstellen, dass die Berechnungen durch die Klasse Money geschützt sind. Das Money-Pattern wurde für mehrere Sprachen wie PHP, Java und JavaScript implementiert. Es liegt nahe, dass die PHP-Implementierung MoneyPHP [4] heißt. Es handelt sich um eine ausgereifte Library, die es seit bereits seit fast zehn Jahren gibt. Listing 1 enthält ein Beispiel für die Verwendung.

Listing 1

use Money\Money; // create an object of 1,23 EUR $net = new Money(123, new Currency('EUR')); // add 19% of tax, round up $gross = $net->multiply('1.19', Money::ROUND_UP); // output is 147, which means 1,47 EUR echo $gross->getAmount();

Mit MoneyPHP können wir uns bei drei Dingen sicher sein: korrekte Dezimalberechnungen, Vermeidung von Fehlern bei der Verwendung mehrerer Währungen und Vermeidung versehentlicher Wertüberschreibungen, da Money ist ein unveränderliches Objekt ist. Jedes Mal, wenn eine Addition, Subtraktion oder eine andere Operation durchgeführt wird, erhalten wir eine neue Instanz der Money-Klasse. Dadurch werden Bugs vermieden, insbesondere wenn Ihre Money-Objekte zwischen mehreren Klassen wechseln, die die komplexe Geschäftslogik Ihrer Anwendung implementieren.

Intern speichert ein Money-Objekt den Betrag immer als String, d. h. in der kleinsten Untereinheit einer Währung. Für Euro ist das der Betrag in Cent, im obigen Beispiel entsprechen 1,23 € 123 Cent. Wenn also ein Eurobetrag vom Benutzer eingegeben wird, muss dieser nur mit 100 multipliziert oder das Dezimaltrennzeichen entfernt werden, um das Money-Objekt zu erstellen. Bei Währungen wie dem japanischen Yen oder dem ungarischen Forint ist es jedoch komplizierter. Der Yen hat aktuell keine Untereinheiten (sehr wohl aber in der Vergangenheit), daher erwartet MoneyPHP den Betrag in Yen. In Forint sind keine Münzen kleiner als 5 Ft im Umlauf, aber die 1/100-Untereinheit wird immer noch für Berechnungen verwendet. Wer Forint verwendet, muss sie für MoneyPHP immer noch mit 100 multiplizieren. Für die Verwendung von verschiedenen Währungen muss daher immer auch auf Details wie die eben erwähnten geachtet werden. Hilfestellung kann die ISO-4217-Liste der Währungen geben [5].

Die Währung richtig formatieren

Wenn wir dem Benutzer einen Geldbetrag darstellen, müssen wir die Sprache und Region berücksichtigen, die der Benutzer bevorzugt. Es reicht nicht aus, ein einfaches echo wie im ersten Listing zu verwenden. Verschiedene Regionen haben unterschiedliche Formatierungsstandards für Zahlen und Währungen. Einige Leute v...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang