在 PHP 中处理货币值的最佳实践?
Posted
技术标签:
【中文标题】在 PHP 中处理货币值的最佳实践?【英文标题】:Best practice for working with currency values in PHP? 【发布时间】:2011-04-18 16:24:59 【问题描述】:我需要在 php 中添加、乘以和比较货币值,并且需要确保它精确到一美分。
一种方法是将所有内容存储在浮点数中,在每次操作之前和之后使用round,在比较相等时使用mind machine epsilon。相当麻烦恕我直言。
另一种方法是将整个数据存储为整数数据类型中的美分,并且记得在我使用数据库(mysql,我使用十进制数据类型)的任何时候来回转换。不优雅,还有很多错误陷阱,恕我直言。
另一种方法是发明我自己的“数据类型”,将所有值存储在字符串中(“34.12”)并创建我自己的数学替换函数。这些函数将在内部将值转换为整数,进行计算并再次将结果输出为字符串。非常复杂,恕我直言。
我的问题:在 PHP 中处理货币值的最佳实践是什么? 谢谢!
【问题讨论】:
【参考方案1】:从 MySQL v5.0.3 开始,MySQLs DECIMAL
数据类型存储精确的十进制数,即不是不准确的浮点表示。
要在 PHP 中正确处理精度数字,请使用 arbitrary precision math functions。这个库在内部操作文本字符串。
货币旨在存储为十进制数字,您可以获得小于美分的货币单位。您应该只在显示数字时对任何值进行四舍五入,而不是在操作或存储期间。
【讨论】:
对不起,我不明白你的意思。 php 中没有十进制数据类型。如果您的意思是浮动:您无法使用它们可靠地测试相等性。 PHP 有一组专门用于处理和比较精度数的函数:php.net/manual/en/ref.bc.php【参考方案2】:2016 年更新:
几年后,希望能更聪明一点;) 由于这个答案仍然偶尔会收到上下投票,我觉得有必要修改我的答案。我绝对不建议再将“钱”存储为整数。唯一真正的答案是 Andrew Dunn 的:使用 Mysql 的 DECIMAL 类型并将 php 的 bc_* 函数封装在 Currency 类中。
为了完整起见,我将在此处保留我过时的答案
您应该始终使用整数。将值存储为整数 您的数据库,使用整数进行计算以及何时且仅在何时, 你想打印它,把它转换成某种可读的格式。
这样你就可以完全规避浮点问题,其中, 一般来说,在用钱工作时是个大问题;)
编辑:值得一提的一件事:您需要考虑精度 在你开始以这种方式工作之前。正如其他人指出的那样,您 可能需要使用小于一美分的值,所以你需要做 你的乘法/除法相应。 (即货币 * 1000 为 .001 精度)
【讨论】:
MySQL 等具有 DECIMAL / NUMERIC 格式,专门用于规避浮点问题并给出准确的结果。 我假设是讽刺,所以我没有投票给你。请确认我是对的:) @Tatu Ulmanen:当然,Mysql 可以。但是如果你在 php 中做一些类似平等测试的事情,你可能会得到意想不到的结果。 +1 假设您不使用小于 1ct 的值。只需在数据库和 php 中都使用整数,然后在显示时转换,就像 Dennis 建议的那样。【参考方案3】:让我自己回答这个问题。最佳做法是创建一个“金额”类。此类在内部将金额存储为整数中的美分,并提供 getter、setter、数学函数,如加法、减法和比较。干净多了。
【讨论】:
这不是,很简单,最佳实践和非常糟糕的建议。请务必封装与任意精度数学函数一起使用的函数,但请不要遵循上述建议。最好的答案是 Andrew Dunn。【参考方案4】:将值保留为美分并使用整数。编写类或辅助函数来封装 UI 中的显示和处理数据库查询中的值。如果你使用浮点数,你会在某处损失一分钱的风险太大。
【讨论】:
【参考方案5】:我尝试在所有数学运算之前将浮点数乘以 100,然后在显示结果之前除以 100。 (成功了!)
从数学上讲,这就像其他人所建议的那样“转换为整数”,但是如果没有任何转换函数,代码看起来要优雅得多。另外,为了避免混淆,我只是在任何值名称的末尾添加了“Cents”。
在机器方面,使用整数而不是浮点数可能更快,但编写人类可读的代码我更喜欢我的解决方案。 (您的里程可能会有所不同,但它在我的应用程序中有效。)
【讨论】:
以上是关于在 PHP 中处理货币值的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章