0

I'm writing a PHP application that deals with monetary values. For this purpose, I use the BigDecimal object from the Brick\Math library. This object allows for precise representations of monetary values and precise operations on them. To create a BigDecimal object out of a string, an int or a float, I have to call the BigDecimal::of method, like so:

BigDecimal::of('1.25');

Now, say that I have the following method:

function withdraw_currency(string $currency, BigDecimal $amount);

If I want to call it, I will often have to create a BigDecimal object, like so:

withdraw_currency('USD', BigDecimal::of('1.25'));

I find this horrendous to read. It does not seem clean at all. It gets worse if the method requires more than one BigDecimal parameter of I'm invoking this method multiple times with, each time, a new BigDecimal object.

I had thought of doing this:

$amount = BigDecimal::of('1.25');
withdraw_currency('USD', $amount);

This is surely more readable, but it feels like the method should be called in one line.

I also thought of changing the withdraw_currency method so that the $amount parameter is a string instead of BigDecimal. $amount would then be converted into a BigDecimal object inside the method; or in other words, it would "hide" the ugliness from the programmer.

Then, the method could be called like so:

withdraw_currency('USD', '1.25');

This looks clean, but it feels wrong as it misleads the programmer into thinking that the method deals with a string, when, in reality, it deals with a BigDecimal object.

It seems like there is no perfect answer, but I wanted the input of other programmers. What would be the "cleanest" way of dealing with the BigDecimal object in that situation?

Pascal Bergeron
  • 761
  • 3
  • 12
  • 27
  • If you're concerned that the function call should be clear about the data types it's using, stick with `withdraw_currency('USD', BigDecimal::of('1.25'));`. If you want to simplify the call but still use numeric values, you could accept an integer argument (cents) and convert it in the function. – kungphu May 07 '20 at 00:38
  • Have you thought about using the [brick/money](https://github.com/brick/money) package? It's based on `brick/math` and makes it easier to pass an [amount, currency] pair around. – BenMorel Aug 18 '20 at 22:53

2 Answers2

0

I think that the last option is the best. Programmers don't generally need to worry about what happens under the hood of the function and you don't want your classes to need to know about what is happening in that function.

-3

Why don’t you use a float? So that you can just type:

withdraw_currency('USD', 1.25);

They are huge in php, 1.7976931348623E+308. Take a look here: floating points

desoss
  • 572
  • 4
  • 26
  • 5
    [_Do not_ use floats for currency values!](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) OP has the right idea using a library that handles decimals reliably. – kungphu May 07 '20 at 00:36
  • 3
    Floats are a really bad idea when it comes to manipulating currency due to rounding errors. The ideal type is a string and using [the BC Math functions](https://www.php.net/manual/en/ref.bc.php) – Matthew Anderson May 07 '20 at 00:36
  • 1
    The reason decimal types like BigDecimal exist at all is to avoid floating point rounding issues and represent currency values *exactly*. Standard IEEE754 binary floating point cannot represent .e.g. 0.01 exactly but decimal can. – President James K. Polk May 07 '20 at 02:20