Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jpinto.ptn's avatar

What's the most efficient way to cache models?

The main purpose of my Laravel projects is managing large amounts of data. Because a lot of it seldom changes, and to easing the load on the database, I implemented some automatic caching features (so a model is cached on update, and something like User::cached(1, 'name') works without any SQL queries). Since I use them on all my projects I was thinking of turning them into a package.

In doing so, I looked into what might be the best way to cache models. I first tried to compare storing the models themselves to storing their attributes only. Storing models had a minor speed advantage (< 4%) but a major memory usage penalty (3x as much, on Redis). Also, loading models was about 10% faster than loading attributes and creating a Model object from them.

To be precise, as "storing attributes" I mean storing the result of $model->getAttributes() and hydrating through (new static())->newFromBuilder($cachedAttributes) when loading.

Are there any ways to optimize this in a meaningful way? Or am I basically stuck between caching low-memory-usage, slightly-slower attributes or high-memory-usage, slightly-faster models? Caching casted attributes rather than their raw value might allow for some middle-ground, but it feels like it might add some added complexity as well.

Any suggestions on how to best approach this problem would be most welcome. Thanks in advance!

0 likes
4 replies
martinbean's avatar

@jpinto.ptn This doesn’t need a package. You just need an abstraction layer, such as a repository.

jpinto.ptn's avatar

@martinbean Thank you for the suggestion. I've never worked with repositories, so I wouldn't know their advantages or disadvantages in this case.

Let's imagine an Order model with multiple Items, each with an amount. When caching an Order, it saves the total amount as well, so I don't have to load its Items every time I want to know an Order amount. Also, whenever an Item is changed, it automatically invalidates the Order cache, so it will be calculated again when necessary.

How about code reusability? With my current code, I just have to add a trait to a model for basic functionality. As for the example above, I would just have to override a preprocessForCache() method to append the order total to the model, and override a cascade() method to Items to flush the parent Order model cache on update.

Would repositories allow for such features?

martinbean's avatar

@jpinto.ptn A repository would mean not touching your models at all, because the caching logic would live in a repository class that is specifically concerned with caching.

Also, in your order example, how would you deal with fetching multiple orders, i.e. with a ->get() or ->paginate() call? Where you don’t know what orders are going to be returned, therefore you don’t know which ones to load from the cache and which ones to fetch from the database.

It’s probably worth familiarising yourself with some common design patterns before diving into, “let’s make a package for this problem”, as you may find that a design pattern or implementing some SOLID principles would be a better solution to the problem at hand.

jpinto.ptn's avatar

@martinbean Whenever a cached model is not found, it's automatically loaded from the DB and cached before being returned. If models are expected to rarely change, the odd uncached model won't cause much of an issue. If many misses are expected, I either populate the cache beforehand or avoid using cache at all. In some cases I repopulate the cache at night, when usage is minimal, to lower the load during heavy usage hours.

The way I handled it, however inefficient it may be, has been working in production for years and I can't afford to refactor everything to a different design pattern at this point. I will look into the repository pattern, see how it might solve my problem, and maybe implement it in the future, when a bigger refactor would be a realistic option. For now, though, I'm most interested in optimizing what I have. Making it a package would make it easier for me to keep it updated between projects. Making it publicly available, should anyone be interested, would just be an extra.

Please or to participate in this conversation.