Tool Spotlight: No Floaters

Tool Spotlight: No Floaters

Using the float type in PHP can be dangerous, because it can introduce rounding errors that can be particularly bothersome if you’re using them to store monetary values. 

Consider the following code:

$adjustment = -1 * (0.1 + 0.2);
var_dump($adjustment === -0.3);

You’d expect the output to be true, indeed, if you use the calculator on your phone you’ll get the value -0.3. But run this code on PHP and you’ll see the output false. This is because PHP’s rounding precision actually evaluates the multiplied value as -0.30000000000000004 even though it would display it as -0.3.

​​https://3v4l.org/vfmjT

This makes using floats in PHP very dangerous, particularly when you’re comparing floating point numbers. This is especially problematic when you’re using float to store monetary values, as these are often compared. It’s an easy trap to fall into, because floats seem like the exact type to use to store currencies that are often displayed to two decimal places.

It’s nearly always better to store monetary values as an integer in the minor unit for that currency, like cent or penny. You can then divide by 100 and use number_format to output the currency in the major/minor unit as expected. 

Not even storing as an integer solves all your rounding problems. Consider dividing 10001 cents by 2. You’re left with 5000.5 or $50 and half a cent. What do we do with that half-cent?  Sadly, there’s not a one-size-fits-all solution to this problem, there will always be some element of monetary rounding, so this is one you should discuss with the team of stakeholders and make a decision on a per-case basis.

Introducing Roave/No-Floaters

When we’re consulting with our clients, we’ve seen this in the wild so many times that we decided we wanted to use static analysis to help catch places where floats had been introduced, either intentionally or not. So we wrote No Floaters – a PHPStan plugin that disallows the use of float either as a keyword in type declarations, or by magic assignment. 

We’ve found it useful, particularly when addressing legacy code-bases where floats have been intentionally (or not!) used in dangerous circumstances.  It might be useful for your code, or at the very least may help you to spot precision rounding errors before they bite you!

1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

 ------ -----------------------------------------------------
  Line   example-file.php
 ------ -----------------------------------------------------
  3      Cannot assign float to $total - floats are not allowed.
 ------ -----------------------------------------------------

 [ERROR] Found 1 error

 
Check out No Floaters on GItHub at https://github.com/roave/no-floaters and explore all our other open-source packages while you’re there.