Understand Laravel Magic: How Eloquent Models Dynamically Retrieves Attributes

Vincent Bergeron • January 24, 2025

I've been working with Laravel for almost eight years, and I think I know Eloquent pretty well. But for a long time, I didn’t fully understand what happens under the hood when accessing properties on a model instance—and I’m sure I’m not the only Laravel developer who felt that way.

Have you ever wondered how Laravel returns the correct value when calling $user->email, even though you never explicitly defined a public $email property on your Eloquent model? Or how Laravel lazy-loads the posts relationship when you call $user->posts, despite there being no posts property on your model?

In this post, I’ll explain how it dynamically retrieves attributes on models and how it leverages PHP's magic methods to make it all work seamlessly.

PHP Overloading and the __get Magic Method

Eloquent models rely on PHP’s overloading capabilities, specifically the __get magic method. This allows to intercept property access and execute custom logic when a property isn't explicitly defined.

When you call $user->email, if the property doesn’t exist, PHP invokes the __get magic method. In the case of Laravel, the __get method is defined on the base Model class. Laravel takes advantage of this to dynamically retrieve the correct value. The diagram below illustrates this flow:

model-attributes-diagram.jpg

Here, "none of the above" means that you're trying to fetch something that does not exist. In this case, an exception will be thrown or null will be returned.

In Laravel 9.35.0, a new Model::shouldBeStrict method was introduced which adds a "strict" mode to Eloquent models. This mode, among other things, will prevent access to non-existent attributes by throwing an exception instead of returning null. If you're not familiar with it, I suggest that you watch this free Laracasts video.