Ich habe einen riesigen Haufen älteren Codes geerbt, der in PHP auf einer MySQL-Datenbank geschrieben wurde. Mir ist aufgefallen, dass die Anwendung doubles
Daten speichert und bearbeitet.
Nun bin ich auf zahlreiche Beiträge gestoßen, in denen erwähnt wurde, dass sie double
aufgrund von Rundungsfehlern nicht für Geldgeschäfte geeignet sind. Ich habe jedoch noch keine vollständige Lösung gefunden, wie monetäre Werte in PHP-Code behandelt und in einer MySQL-Datenbank gespeichert werden sollen.
Gibt es eine bewährte Methode für den Umgang mit Geld speziell in PHP?
Dinge, die ich suche, sind:
- Wie sollen die Daten in der Datenbank gespeichert werden? Spaltentyp? Größe?
- Wie sollen die Daten bei normaler Addition, Subtraktion behandelt werden. Multiplikation oder Division?
- Wann sollte ich die Werte runden? Wie viel Rundung ist akzeptabel, wenn überhaupt?
- Gibt es einen Unterschied zwischen dem Umgang mit hohen und niedrigen Geldwerten?
Hinweis: Ein SEHR vereinfachter Beispielcode, wie ich im Alltag auf Geldwerte stoßen könnte (verschiedene Sicherheitsbedenken wurden zur Vereinfachung ignoriert. Natürlich würde ich meinen Code im wirklichen Leben niemals so verwenden):
$a= $_POST['price_in_dollars']; //-->(ex: 25.06) will be read as a string should it be cast to double?
$b= $_POST['discount_rate'];//-->(ex: 0.35) value will always be less than 1
$valueToBeStored= $a * $b; //--> any hint here is welcomed
$valueFromDatabase= $row['price']; //--> price column in database could be double, decimal,...etc.
$priceToPrint=$valueFromDatabase * 0.25; //again cast needed or not?
Ich hoffe, dass Sie diesen Beispielcode verwenden, um mehr Anwendungsfälle herauszubringen und ihn nicht wörtlich zu nehmen.
Bonus - Frage Wenn ich ein ORM wie Lehre oder PROPEL zu verwenden, wie anders wird es Geld in meinem Code zu verwenden sein.
decimal
Typ in C # hat eine begrenzte Genauigkeit, ist aber perfekt für Geldwerte geeignet.Antworten:
Es kann sehr schwierig sein, mit PHP / MySQL mit Zahlen umzugehen. Wenn Sie eine Dezimalzahl (10,2) verwenden und Ihre Zahl länger ist oder eine höhere Genauigkeit aufweist, wird sie ohne Fehler abgeschnitten (es sei denn, Sie haben den richtigen Modus für Ihren Datenbankserver festgelegt).
Um große Werte oder hochpräzise Werte zu verarbeiten, können Sie eine Bibliothek wie BCMath verwenden , mit der Sie grundlegende Operationen für große Zahlen ausführen und die erforderliche Präzision beibehalten können.
Ich bin mir nicht sicher, welche genauen Berechnungen Sie durchführen werden, aber Sie müssen auch bedenken, dass (0,22 * 0,4576) + (0,78 * 0,4576) nicht gleich 0,4576 ist, wenn Sie nicht die richtige Präzision während des Prozesses verwenden.
Die maximale Größe von DECIMAL in MySQL beträgt 65, es sollte also für jeden Zweck mehr als genug sein. Wenn Sie den Feldtyp DECIMAL verwenden, wird dieser unabhängig von der Verwendung eines ORM oder eines einfachen PDO / mysql (i) als String zurückgegeben.
DECIMAL mit der Präzision, die Sie brauchen. Wenn Sie Wechselkurse verwenden, benötigen Sie mindestens vier Dezimalstellen
Verwenden Sie BCMath, um auf der sicheren Seite zu sein, und warum die Verwendung von float möglicherweise keine gute Idee ist
Für Geldwerte sind normalerweise zwei Dezimalstellen zulässig, aber Sie benötigen möglicherweise mehr, wenn Sie beispielsweise Wechselkurse verwenden.
Kommt drauf an, was du meinst. Es gibt definitiv einen Unterschied zwischen der Handhabung von Zahlen mit hoher Präzision.
quelle
Eine einfache Lösung besteht darin, sie als ganze Zahlen zu speichern. 99,99 gespeichert als 9999. Wenn dies nicht funktioniert (und es gibt viele Gründe, warum dies eine schlechte Wahl sein könnte), können Sie den Typ Dezimal verwenden. http://dev.mysql.com/doc/refman/5.0/de/precision-math-decimal-changes.html auf der MySQL-Seite. Auf der PHP-Seite habe ich diese /programming/3244094/decimal-type-in-php gefunden, die genau das sein könnte, wonach Sie suchen.
Bonusfrage: Schwer zu sagen. Der Orm wird basierend auf den ausgewählten Datentypen funktionieren. Ich würde sagen, dass Sie einige Dinge mit Abstraktion tun könnten, um zu helfen, aber dieses spezielle Problem wird nicht einfach durch den Wechsel zu einem ORM gelöst.
quelle
Ich werde versuchen, meine Erfahrung in diese zu stecken:
Ich habe
DECIMAL(10,2)
für MySQL ohne Probleme verwendet (8 Abschlüsse und 2 Dezimalstellen == 99,999,999,99 == große Menge), aber dies hängt von der Geldmenge ab, die Sie abdecken müssen. Bei großen Mengen ist besondere Vorsicht geboten (z. B. maximale OS-Schwebewerte). Im Dezimalteil verwende ich 2 Werte, um das Abschneiden oder Runden von Werten zu vermeiden. Es gibt nur wenige Fälle, in denen Sie mehr Dezimalzahlen benötigen (in diesem Fall müssen Sie sicherstellen, dass der Benutzer mit allen Daten arbeitet, da sonst die Daten unbrauchbar werden).Arbeiten Sie mit einer Währung und einer Umrechnungstabelle (mit Daten). Auf diese Weise stellen Sie sicher, dass immer der richtige Betrag gespeichert wird. Ein Extra: Speichern Sie komplette Werte und erstellen Sie eine Ansicht mit Berechnungsergebnissen. Auf diese Weise können Sie schnell Werte festlegen
Auch dies hängt von der Geldmenge Ihres Systems ab. Denken Sie immer in KISS-Begriffen, es sei denn, Sie müssen in das Chaos der Wechselstube geraten
Abhängig von Ihrem Betriebssystem und Ihren Programmiersprachen müssen Sie immer Ihre Maximal- und Minimalwerte überprüfen
quelle
$valueToBeStored= $a * $b;
if umgehen muss$a
und$b
beide als Dezimalstellen aus der Datenbank gelesen werden, denke ich, dass siedouble
in PHP umgewandelt werden, oder? Wird das die Zahlen beeinflussen?$a
und$b
von db genommen? In meinem Beispiel müssen Sie also niemals speichern,$valueToBeStored
da Sie immer die Quelle$a
und die$b
Daten haben. So können Sie den Wert in einer Funktion oder so programmgesteuert bearbeiten oder eine MySQL-Ansicht mit dem Spaltenergebnis erstellen. Auf diese Weise müssen Sie sich keine Sorgen machen, wenn ein Wert geändert werden muss (fehleranfällig)