使用 moontoast/math 计算金额
2019年3月25日我们在代码中使用了 PHP 的官方扩展 bcmath
提供的函数来进行金额计算,这是为了避免浮点数运算不精确的问题。但是 bcmath
函数用起来很不方便,我们通常会使用 moontoast/math
这个库来作为替代,这个库的底层也是依赖于 bcmath
,主要是做了面向对象的封装。
1 |
$ composer require moontoast/math |
这个库主要提供了 \Moontoast\Math\BigNumber
这个类,这个类的构造函数接受两个参数,第一个参数就是我们要参与运算的数值,第二个参数是可选参数,用于表示我们希望的计算精度(即精确到小数点后几位)。
同时这个类提供了许多常见的算术运算方法,比如 加法 add()
、减法 subtract()
、乘法 multiply()
、除法 divide()
等等。
现在修改我们之前计算金额的代码:
修改前:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * 创建一个属性访问器,返回当前还款计划需要还款的总金额 * @return string */ public function getTotalAttribute() { $total = bcadd($this->base, $this->fee, 2); #小数点计算需要用 bcmath 扩展提供的函数 本金加+手续费 if (!is_null($this->fine)) { #判断是否存在续期费用 $total = bcadd($total, $this->fine, 2); #总金额+预期费用 } return $total; } |
修改后:
1 2 3 4 5 6 7 8 9 |
public function getTotalAttribute() { $total = (new BigNumber($this->base, 2))->add($this->fee); #小数点计算需要用 bcmath 扩展提供的函数 本金加+手续费 if (!is_null($this->fine)) { #判断是否存在续期费用 $total->add($this->fine); #总金额+预期费用 } return $total->getValue(); } |
是每次使用都要 new
一次对象并且设定精度,还是比较麻烦的,我们可以在 helpers.php
里创建一个辅助函数来方便我们调用:
1 2 3 4 5 6 7 8 9 10 |
/** * 自定义方法 默认的精度为小数点后两位 * @param $number * @param int $scale * @return \Moontoast\Math\BigNumber */ function big_number($number, $scale = 2) { return new \Moontoast\Math\BigNumber($number, $scale); } |
再次修改:
1 2 3 4 5 6 7 8 9 |
public function getTotalAttribute() { $total = big_number($this->base)->add($this->fee); #本金加+手续费 if (!is_null($this->fine)) { #判断是否存在续期费用 $total->add($this->fine); #总金额+预期费用 } return $total->getValue(); } |