$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[July 21, 2025] Eloquent ORM

Eloquent Computed Attributes: Accessors

Eloquent Computed Attributes: Accessors

────────────────────────────────────────────────────────

Eloquent Computed Attributes: Accessors

Tip: Attribute Accessor

protected function fullName(): Attribute
{
    return Attribute::make(
        get: fn() => "{$this->first_name} {$this->last_name}"
    );
}

Gotcha: Appends for Serialization

protected $appends = ['full_name'];

Without $appends, the accessor won't appear in toArray().

Tip: Computed with Relations

protected function commentCount(): Attribute
{
    return Attribute::make(
        get: fn() => $this->comments()->count()
    );
}

Gotcha: Performance Impact

Accessors run every time the attribute is accessed. Cache expensive computations.

Tip: Setter Accessor

protected function name(): Attribute
{
    return Attribute::make(
        get: fn($value) => ucfirst($value),
        set: fn($value) => strtolower($value),
    );
}

Gotcha: Accessors and where()

Accessors don't affect database queries. where('full_name', 'John') won't work.

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

Computed attributes via accessors are convenient, but they can introduce subtle bugs when used in queries. An accessor modifies the returned value but doesn't change the database value, so where() conditions operate on the stored value, not the accessor output. I've seen teams confused about why where('price', '>', 100) returns records with formattedPrice below 100. The accessor is a presentation layer concern, not a query filter.

Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)

────────────────────────────────────────────────────────
<-- back to posts