Dealing with monetary values in any application is something you have to get right the first time. Without the correct approach, you risk displaying prices incorrectly or worse, making miscalculations.
Here's how to work with money properly in Laravel.
The golden rule when storing prices is never use a float or a double. This might seem strange at first because we typically think of money represented as a float value (like 5.67 for $5.67).
When dealing with money, we need precision. Floating point numbers have rounding errors. For basic outputting of prices, you could use a float, but any kind of comparison or calculation with these values could result in weird behaviour.
Aside from this, it's just plain awkward to calculate with floats. Let's see an example.
Here's what defining a column on a Product
model would look like with the wrong approach:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->float('price');
$table->timestamps();
});
Now imagine we have a 25% sale and want to calculate the discount a customer would receive on an item priced $8.99
. Here's a rough example of calculating this:
$product = Product::find(1);
$couponPercentage = 25;
$discount = ($product->price * $couponPercentage) / 100; // 2.2475
So the end result is 2.2475
. The actual amount we'd want to take off is 2.25
. And now we're left figuring out how to properly round this number with 4 decimal places. Imagine if things got more complex than this? (let's not).
The solution to all this is to use an integer
to store money in cents (or whatever monetary unit you use).
Let's change up our migration:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->unsignedInteger('price');
$table->timestamps();
});
We use an unsignedInteger
here, which can hold a larger positive value and no negative value, since we don't need negative prices.
To populate prices, you'll now need to multiply the price by 100. Therefore, 8.99
is stored as 899
.
Let's look at the same example from earlier, where we want to calculate a 25% discount on this, and see how much easier it is.
$product = Product::find(1);
$couponPercentage = 25;
Look again at that dot. That's here. That's home. That's us. On it everyone you love, everyone you know, everyone you ever heard of, every human being who ever was, lived out their lives.