Dealing with Money in Laravel

September 30th, 2024 • 6 minutes read time

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();
});
This is a premium article
Members get access to all articles, plus hundreds of screencasts.
Check it out
Already a member? Sign in to continue

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.

Author
Alex Garrett-Smith
Share :

Comments

No comments, yet. Be the first!