1

I have been building an application with Laravel 5.0 and locally (within homestead) everything works as expected.

However, when I deploy the project a number of issues are apparent. One of which involves floats.

Homestead is PHP 5.6 whilst my server is 5.5.9. When I view a price on my local system it appears correctly as 9.99. However, on my server it does not display correctly but instead as 9.99000.

My schema has price fields set to float(12,5), hence the additional right padding, this is also required.

My question is simply what is the difference between PHP 5.5 and 5.6 (or even PDO/Eloquent) that would cause a floating point issue?

Ash
  • 3,242
  • 2
  • 23
  • 35
  • What's the code that is responsible for outputting those values? – Bogdan Apr 13 '16 at 22:15
  • It's standard eloquent. If I `{{ $product->price}}` php 5.5 will display `9.99000` where as php 5.6 will display `9.99`. – Ash Apr 13 '16 at 22:18
  • Is the RDBMS version different as well from dev to production? – Bogdan Apr 13 '16 at 22:19
  • @Bogdan Both servers use Mysql 5.7.9 – Ash Apr 13 '16 at 22:22
  • The logical point of origin would be PDO since that's the layer responsible for processing that particular piece of information (since Eloquent is database agnostic and MySQL versions are the same, from a logical standpoint the issue should be on the PHP side). I'll take a look tomorrow and see if I can reproduce it (unless someone else comes with an explanation until then). – Bogdan Apr 13 '16 at 22:31
  • @Bogdan thanks, you've 100% confirmed my very thoughts, hense my question. I too will try some PDO queries/results; but any additional help is also appreciated. – Ash Apr 13 '16 at 22:32
  • Regardless of the difference between php versions it's a **very bad** idea to use floats for monetary values. Consider using a fixed-point type i.e. DECIMAL or its analogues depending on your RDBMS. Better yet use integer and store monetary values in cents/pennies. – peterm Apr 13 '16 at 22:44
  • @peterm I agree that would be better however refactoring the whole system is not an option at this point. I need to solve this problem and fast – Ash Apr 13 '16 at 22:47
  • You can use the round() function to temporarily solve your problem – Claudio King Apr 13 '16 at 22:55
  • Can you show the results of `{{ gettype($product->price) }}` from both servers? I'm assuming that on Homestead it will show as "double", but on your server it will show as "string". If so, your server probably is not using the mysql native driver (`mysqlnd`). You can check by running `php -i | grep mysqlnd`. If it doesn't show anything, then you need to remove `php5-mysql` and install `php5-mysqlnd`. – patricus Apr 14 '16 at 01:58
  • You can try with attribute casting, since you may not always be able to swap MySQL drivers (e.g. `protected $casts = ['price' => 'float']`). [Docs](https://laravel.com/docs/5.0/eloquent#attribute-casting) – Oliver Maksimovic Apr 14 '16 at 10:23
  • @drndavi I tried this and it did not solve my problem, it converted `"9.99000"` into `9.99000` *(which is expected but not intended)*. – Ash Apr 14 '16 at 10:25
  • @peterm Also, decimals are doubles/floats and in finance, yes you can work in pence/cents *(providing amounts are no less than 1 pence/1 cent)*. However, in e-commerce this is not always accurate. Some businesses do sell products at fractions of pence/cents - say a company who sells sheet metal at 10.456780 per 1kg and their calculator must be accurate to the very half pence/cent. This is also the same in automotive/upholstery industries dealing with length, width, or volume *(in liquid)* – Ash Apr 14 '16 at 10:32

1 Answers1

2

There's no difference between the PHP versions that would cause this. There are differences between different mysql drivers, however, and that could cause the issue that you are seeing.

Homestead comes with php5-mysqlnd installed, which is the "MySql Native Driver". When using this driver, floating points and integers fetched from the database will be assigned as numeric datatypes in PHP. If you are not using the native driver (php5-mysql), floating points and integers fetched from the database will be assigned as strings in PHP.

The following code demonstrates how this affects your output:

$f = 9.99000;
$s = "9.99000";

echo $f; // shows 9.99
echo $s; // shows 9.99000

You can check to see if the server is using the native driver with the command php -i | grep mysqlnd. This is just searching through your phpinfo() for any mention of the native driver. If this doesn't return anything, then you are not using the native driver, and your numeric data will be returned as strings.

If you do not have the native driver installed, you will need to remove the old driver and install the new driver:

apt-get remove php5-mysql

apt-get install php5-mysqlnd

Assuming this was your issue in the first place, this will fix it. You can also check out this question and answer for more information.

Community
  • 1
  • 1
patricus
  • 59,488
  • 15
  • 143
  • 145
  • Wow, thanks. I've learnt something new here and thanks for the link I wish I could've found that. – Ash Apr 14 '16 at 06:28