Laravel 13 Attribute Guide: Transitioning from Properties to PHP Attributes

Overview

introduces a significant shift in how developers configure classes by implementing 36 new
PHP
attributes. These attributes replace traditional protected properties—like $fillable or $hidden—with metadata directly above the class or method definition. This change aims to clean up class bodies and utilize native PHP 8 language features for better static analysis and cleaner syntax.

Prerequisites

To use these features, you should have a solid grasp of

attribute syntax (#[Attribute]). You should also be familiar with
Laravel
's
Eloquent
ORM, job dispatching, and
Artisan
command structures.

Key Libraries & Tools

  • Laravel
    : The latest version of the PHP framework.
  • Eloquent
    : The database mapper now supporting attribute-based model configuration.
  • Livewire
    : Often paired with these attributes in modern starter kits.
Laravel 13 Attribute Guide: Transitioning from Properties to PHP Attributes
New in Laravel 13: Added 36 (!) PHP Attributes

Code Walkthrough

Refactoring Eloquent Models

Previously, you defined model behavior using class properties. In the new version, you apply them as attributes:

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;

#[Fillable(['name', 'email'])]
#[Hidden(['password'])]
class User extends Model {}

Laravel reads these attributes at runtime, effectively populating the internal protected properties for you.

Enhancing Queued Jobs

For background tasks, you can now set retry limits and timeouts directly on the class:

use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;

#[Tries(5)]
#[Timeout(60)]
class ProcessPodcast implements ShouldQueue {}

Syntax Notes

Attributes utilize the #[ ] syntax. Unlike properties, attributes can take constructor arguments, allowing for cleaner configuration of complex settings like ExponentialBackoff within a single line. This moves configuration logic out of the class body and into the header.

Practical Examples

You can now define

command signatures and descriptions without declaring variables:

#[Signature('app:send-emails {user}')]
#[Description('Send a notification email to a specific user')]
class SendEmails extends Command {}

Tips & Gotchas

While

now defaults to this style in its starter kits, these attributes are strictly optional. If you find multiple attributes on a single controller method hard to read, stick to the traditional $middleware arrays. Additionally, always ensure you import the correct namespace for each attribute to avoid "Attribute not found" errors.

Laravel 13 Attribute Guide: Transitioning from Properties to PHP Attributes

Fancy watching it?

Watch the full video and context

2 min read