Eloquent Appending: Virtual Attributes
Eloquent Appending: Virtual Attributes
Eloquent Appending: Virtual Attributes
Tip: $appends for Serialized Attributes
protected $appends = ['full_name'];
protected function fullName(): Attribute
{
return Attribute::make(
get: fn() => "{$this->first_name} {$this->last_name}"
);
}
full_name appears in toArray() and JSON.
Gotcha: $appends Runs on Every Serialization
Even if you don't need the attribute, it's computed. This can be expensive for complex logic.
Tip: Conditional Appending
public function toArray(): array
{
$array = parent::toArray();
if ($this->include_details) {
$array['full_name'] = $this->full_name;
}
return $array;
}
Gotcha: makeHidden() Removes Attributes
$user->makeHidden(['email', 'password']);
Temporarily hides attributes from serialization.
Tip: makeVisible() for Hidden Attributes
$user->makeVisible(['created_at']);
Shows attributes that were hidden by the model.
Gotcha: Appends Don't Work with select()
If you select() specific columns, appended attributes still compute but selected columns may be missing data the accessor needs.
Tip: Use cursor() for Memory-Neutral Iteration
When exporting 100K rows, get() loads everything into memory. cursor() uses yield and keeps memory flat regardless of row count. Perfect for artisan commands.
Tip: whereHas() vs load() — Two Different Things
whereHas() filters the parent query by relationship existence. load() eager-loads relationships AFTER the query. Mixing them up is a common source of logic bugs.
Gotcha: withCount() Adds a Subquery
withCount('comments') runs a correlated subquery on every row. On large tables, this can be slower than a separate query. Profile before relying on it.
Senior Insight
The appends property on Eloquent models is convenient but dangerous — every serialized response includes those attributes, even when they're not needed. I've seen API responses balloon from 20KB to 200KB because a model appended an expensive computed attribute that triggered multiple database queries. My rule: never put accessor-based attributes in appends. Instead, load them explicitly in API resources with when() or merge() when the response actually needs them.
Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)