使用PHP中的货币值的最佳实践?

时间:2021-09-23 21:15:11

I need to add, multiply and compare currency values in PHP and need to be sure that it is exact down to a single cent.

我需要在PHP中添加、复制和比较货币值,并且需要确定它精确到一分钱。

One way is to store everything in float, use round before and after each operation and mind machine epsilon when comparing for equality. Quite cumbersome imho.

一种方法是将所有东西都存储在浮点数中,在每次操作前后使用循环,并在比较相等时使用mind machine epsilon。很繁琐的清规戒律。

Another way is to store the whole thing as cents in integer data types, plus remember to convert back and forth anytime I work with the database (mysql, where I use the decimal data type). Inelegant, and many error pitfalls, imho.

另一种方法是将整个数据存储为整数数据类型中的分值,并且记住,在使用数据库(mysql,我使用十进制数据类型)时,要来回转换。不雅,还有很多错误陷阱,等等。

Another way is to invent my own "datatype", store all values in strings ("34.12") and create my own mathematical replacement functions. These function would convert the value to integers internally, do the calculation and output the result again a strings. Suprisingly complicated, imho.

另一种方法是创建我自己的“datatype”,将所有值存储在字符串中(“34.12”),并创建自己的数学替换函数。这些函数会在内部将值转换为整数,计算并输出结果。令人惊奇的是复杂的,恕我直言。

My question: what is the best practice for working with currency values in PHP? Thanks!

我的问题是:在PHP中处理货币值的最佳实践是什么?谢谢!

4 个解决方案

#1


23  

As of MySQL v5.0.3, MySQLs DECIMAL datatype stores an exact decimal number, i.e. not an inaccurate floating point representation.

在MySQL v5.0.3中,MySQLs十进制数据类型存储一个精确的十进制数,即不是不准确的浮点表示。

To correctly manipulate precision numbers in PHP use the arbitrary precision math functions. Internally this library manipulates text strings.

要正确地操作PHP中的精度数,可以使用任意的精度数学函数。这个库在内部操作文本字符串。

Currency is intended to be stored as a decimal number, you can get units of money smaller than cents. You should only round any values when displaying the figures, not during manipulation or storage.

货币以十进制的形式存储,你可以得到小于美分的货币单位。您应该只在显示图形时使用任何值,而不是在操作或存储期间。

#2


5  

Let me answer this myself. Best practice would be to create a "money amount" class. This class stores the amount internally as cents in integers, and offers getters, setters, math functions like add, subtract and compare. Much cleaner.

让我自己来回答这个问题。最佳实践是创建一个“金额”类。这个类将内部的金额存储为整数中的美分,并提供getter、setter、add、subtract和compare等数学函数。更加清晰。

#3


3  

Update 2016:

2016年更新:

A couple of years later and hopefully a little bit wiser ;)
Since this answer still receives the occasional up- and down vote I felt the need to revise my answer. I absolutely do not advise storing 'money' as integers anymore. The only true answer is Andrew Dunn's: Use Mysql's DECIMAL type and encapsulate php's bc_* functions in a Currency class.

几年后,我希望自己变得更聪明一点;由于这个答案仍然偶尔会有上下投票,我觉得有必要修改我的答案。我绝对不建议将“钱”存储为整数。唯一正确的答案是Andrew Dunn的:使用Mysql的十进制类型,在一个货币类中封装php的bc_*函数。


I will keep my outdated answer here for completeness sake

为了完整性起见,我将在这里保留过时的答案

You should always work with integers. Store the values as ints in your database, use ints to do calculations and when, and only when, you want to print it, convert it to some readable format.

你应该一直使用整数。将值存储为数据库中的ints,使用ints进行计算,并只在需要打印时将其转换为可读格式。

This way you completeley circumvent floating point problems, which, generally, is a big problem when working with money ;)

通过这种方式,你完全可以绕过浮点问题,这通常是在使用金钱时遇到的一个大问题;

Edit: One thing worth mentioning: You need to think about precision before you start working this way. As others have pointed out, you might need to work with values smaller than a cent, so you need to do your multiplication/division accordingly. (ie currency * 1000 for a .001 precision)

编辑:有一件事值得一提:在开始工作之前,你需要考虑一下精确。正如其他人指出的那样,您可能需要处理小于一分的值,因此您需要相应地做乘法/除法。(即货币* 1000,精度为0.001)

#4


0  

Keep the values as cents and use integers. Write classes or helper functions to encapsulate displaying in the UI and handling values in your database queries. If you use float, there is too much risk you'll lose a cent somewhere.

将值保留为美分并使用整数。编写类或助手函数来封装在UI中显示和处理数据库查询中的值。如果你使用float,风险太大,你会在某处损失一分钱。

#1


23  

As of MySQL v5.0.3, MySQLs DECIMAL datatype stores an exact decimal number, i.e. not an inaccurate floating point representation.

在MySQL v5.0.3中,MySQLs十进制数据类型存储一个精确的十进制数,即不是不准确的浮点表示。

To correctly manipulate precision numbers in PHP use the arbitrary precision math functions. Internally this library manipulates text strings.

要正确地操作PHP中的精度数,可以使用任意的精度数学函数。这个库在内部操作文本字符串。

Currency is intended to be stored as a decimal number, you can get units of money smaller than cents. You should only round any values when displaying the figures, not during manipulation or storage.

货币以十进制的形式存储,你可以得到小于美分的货币单位。您应该只在显示图形时使用任何值,而不是在操作或存储期间。

#2


5  

Let me answer this myself. Best practice would be to create a "money amount" class. This class stores the amount internally as cents in integers, and offers getters, setters, math functions like add, subtract and compare. Much cleaner.

让我自己来回答这个问题。最佳实践是创建一个“金额”类。这个类将内部的金额存储为整数中的美分,并提供getter、setter、add、subtract和compare等数学函数。更加清晰。

#3


3  

Update 2016:

2016年更新:

A couple of years later and hopefully a little bit wiser ;)
Since this answer still receives the occasional up- and down vote I felt the need to revise my answer. I absolutely do not advise storing 'money' as integers anymore. The only true answer is Andrew Dunn's: Use Mysql's DECIMAL type and encapsulate php's bc_* functions in a Currency class.

几年后,我希望自己变得更聪明一点;由于这个答案仍然偶尔会有上下投票,我觉得有必要修改我的答案。我绝对不建议将“钱”存储为整数。唯一正确的答案是Andrew Dunn的:使用Mysql的十进制类型,在一个货币类中封装php的bc_*函数。


I will keep my outdated answer here for completeness sake

为了完整性起见,我将在这里保留过时的答案

You should always work with integers. Store the values as ints in your database, use ints to do calculations and when, and only when, you want to print it, convert it to some readable format.

你应该一直使用整数。将值存储为数据库中的ints,使用ints进行计算,并只在需要打印时将其转换为可读格式。

This way you completeley circumvent floating point problems, which, generally, is a big problem when working with money ;)

通过这种方式,你完全可以绕过浮点问题,这通常是在使用金钱时遇到的一个大问题;

Edit: One thing worth mentioning: You need to think about precision before you start working this way. As others have pointed out, you might need to work with values smaller than a cent, so you need to do your multiplication/division accordingly. (ie currency * 1000 for a .001 precision)

编辑:有一件事值得一提:在开始工作之前,你需要考虑一下精确。正如其他人指出的那样,您可能需要处理小于一分的值,因此您需要相应地做乘法/除法。(即货币* 1000,精度为0.001)

#4


0  

Keep the values as cents and use integers. Write classes or helper functions to encapsulate displaying in the UI and handling values in your database queries. If you use float, there is too much risk you'll lose a cent somewhere.

将值保留为美分并使用整数。编写类或助手函数来封装在UI中显示和处理数据库查询中的值。如果你使用float,风险太大,你会在某处损失一分钱。