MySQLデータベースの上にPHPで書かれたレガシーコードの膨大な山を継承しました。私が気付いたことは、アプリケーションがデータの保存と操作にdoubles
を使用していることです。
今度は、丸め誤差が原因でdouble
が通貨操作に適さない方法について言及している多数の投稿に出くわしました。ただし、金額の値をPHPコードで処理し、MySQLデータベースに保存する方法を説明するための完全なソリューションはまだありません。
特にPHPでお金を処理することに関して、ベストプラクティスはありますか?
私が探しているものは次のとおりです。
注: A [〜#〜] very [〜#〜]日常生活でお金の価値に遭遇する可能性のあるサンプルコードの簡略化(さまざまなセキュリティ上の懸念は、簡略化のために無視されました)。もちろん、実際には私はこのようなコードを決して使用しません):
$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?
このサンプルコードは、より多くのユースケースを引き出す手段として使用し、文字どおり当然使用しないことを願っています。
ボーナス質問 DoctrineまたはPROPELなどのORMを使用する場合、コードでお金を使用することとどのように異なるでしょうか。
PHP/MySQLで数値を処理するのは非常に難しい場合があります。 decimal(10,2)を使用し、数値が長いか精度が高い場合、(dbサーバーに適切なモードを設定しない限り)エラーなしで切り捨てられます。
大きな値や高精度の値を処理するには、 BCMath のようなライブラリを使用できます。これにより、大きな数値に対して基本的な操作を実行し、必要な精度を維持できます。
正確にどのような計算を行うかはわかりませんが、プロセスで適切な精度を使用しない場合、(0.22 * 0.4576)+(0.78 * 0.4576)は0.4576に等しくないことにも注意してください。
MySQLのDECIMALの最大サイズは65であるため、どのような目的にも十分な大きさでなければなりません。 DECIMALフィールドタイプを使用する場合、ORMの使用や単純なPDO/mysql(i)の使用に関係なく、文字列として返されます。
データはデータベースにどのように保存する必要がありますか?カラム型?サイズ?
必要な精度の10進数。為替レートを使用している場合、少なくとも小数点第4位が必要になります。
通常の加算、減算でデータをどのように処理するか。乗算または除算?
BCMathを使用して保存側にし、なぜ float を使用するのが良い考えではないのか
いつ値を丸める必要がありますか?丸めはどの程度許容されますか?
金額の場合、通常の小数点以下2桁は許容されますが、たとえば為替レートを使用している場合は、さらに必要になる場合があります。
大きい金額と低い金額の処理に違いはありますか?
大まかにあなたが何を意味するかによる。高精度の数値の処理には間違いなく違いがあります。
簡単な回避策は、それらを整数として格納することです。 99.99は9999として格納されます。これが機能しない場合(そしてこれが不適切な選択である理由がたくさんある場合)、Decimalタイプを使用できます。 http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html mysql側。 php側でこれを見つけました https://stackoverflow.com/questions/3244094/decimal-type-in-php これはあなたが探しているものかもしれません。
おまけの質問:言うのは難しい。 ormは、選択したデータ型に基づいて機能します。あなたは抽象化を使っていくつかのことを行うことができると思いますが、この特定の問題は単にORMに移行することによって対処されません。
私はこれに私の経験を入れようとします:
私が探しているものは次のとおりです。
データはデータベースにどのように保存する必要がありますか?カラム型?サイズ?
私はmysqlでDECIMAL(10,2)
を問題なく使用してきました(8完全な2小数点== 99.999.999,99 ==莫大な量)が、これはカバーする必要がある金額の範囲によって異なります。莫大な量は特に注意を払う必要があります(たとえば、OSの最大浮動小数点値)。小数部では、値の切り捨てや丸めを避けるために2つの値を使用します。お金を稼ぐことは、より多くの小数が必要なケースはほとんどありません(その場合、ユーザーがすべての小数を処理できることを確認する必要があります。そうでない場合、役に立たないデータです)
通常の加算、減算でデータをどのように処理するか。乗算または除算?
1つの通貨と為替表(日付付き)を操作します。このようにして、常に正しい金額が保存されるようにします。追加:完全な値を保存し、計算結果を含むビューを作成します。これは、オンザフライで値を修正するのに役立ちます
いつ値を丸める必要がありますか?丸めはどの程度許容されますか?
繰り返しますが、システムのお金の範囲に依存します。 KISS用語で考える)
大きい金額と低い金額の処理に違いはありますか?
OSとプログラミング言語によっては、最大値と最小値を常に確認する必要があります