Zum Hauptinhalt springen

Was sind PHP-Attribute?

PHP-Attribute (PHP Attributes) sind eine native, in PHP 8.0 eingeführte Syntax für Metadaten. Sie können Klassen, Methoden, Eigenschaften oder Funktionen mit Metainformationen in der Form #[AttributeName] versehen. Laravel setzt PHP-Attribute im Framework selbst intensiv ein und ermöglicht damit die deklarative Konfiguration von Jobs und Eloquent-Modellen. In Laravel 13 (v13.2.0) akzeptieren die Queue-Attribute nun auch Enums. Anstelle klassischer Klasseneigenschaften oder Methodenüberschreibungen können Sie mit Attributen lesbaren, kompakten Code schreiben.
// Klassische Schreibweise
class ProcessOrder implements ShouldQueue
{
    public string $queue = 'orders';
    public string $connection = 'redis';
    public int $tries = 3;
    public array $backoff = [30, 60, 120];
}

// Schreibweise mit Attributen
#[Queue('orders')]
#[Connection('redis')]
#[Tries(3)]
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
}
Attribute stehen ab PHP 8.0 zur Verfügung. Da Laravel 13 PHP 8.3 oder höher voraussetzt, können Sie Attribute in allen Umgebungen verwenden.

Queue-bezogene Attribute

Alle Attribute für Queue-Jobs liegen im Namensraum Illuminate\Queue\Attributes.

#[Queue] — Queue-Namen angeben

Gibt die Standard-Queue an, an die der Job gesendet wird.
use Illuminate\Queue\Attributes\Queue;

#[Queue('emails')]
class SendWelcomeEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle(): void
    {
        // ...
    }
}
Ab v13.2.0 kann statt einer Zeichenkette auch ein Enum übergeben werden.
enum QueueName: string
{
    case Emails = 'emails';
    case Orders = 'orders';
    case Notifications = 'notifications';
}

#[Queue(QueueName::Emails)]
class SendWelcomeEmail implements ShouldQueue
{
    // ...
}
Das Attribut #[Queue] ist auf Attribute::TARGET_CLASS gesetzt und kann daher nur auf Klassen angewendet werden.

#[Connection] — Verbindung angeben

Gibt die Standard-Queue-Verbindung an, die der Job nutzt.
use Illuminate\Queue\Attributes\Connection;

#[Connection('sqs')]
class ProcessPayment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle(): void
    {
        // ...
    }
}
Auch hier funktionieren Enums.
enum QueueConnection: string
{
    case Redis = 'redis';
    case Sqs = 'sqs';
    case Database = 'database';
}

#[Connection(QueueConnection::Sqs)]
class ProcessPayment implements ShouldQueue
{
    // ...
}

#[Backoff] — Backoff-Zeit für Retries angeben

Gibt die Wartezeit (in Sekunden) bis zum erneuten Versuch nach einem fehlgeschlagenen Job an. Mit mehreren Werten können Sie unterschiedliche Wartezeiten pro Retry setzen (variadic).
use Illuminate\Queue\Attributes\Backoff;

// Feste Wartezeit (bei allen Retries 60 Sekunden)
#[Backoff(60)]
class SendEmail implements ShouldQueue
{
    // ...
}

// Unterschiedliche Wartezeiten pro Retry (exponentielles Backoff)
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
Ein Blick in die Implementierung von Backoff zeigt, dass die Klasse für variadic Argumente ausgelegt ist.
// Implementierung von Illuminate\Queue\Attributes\Backoff
#[Attribute(Attribute::TARGET_CLASS)]
class Backoff
{
    public array|int $backoff;

    public function __construct(array|int ...$backoff)
    {
        $this->backoff = count($backoff) === 1 ? $backoff[0] : $backoff;
    }
}
Ein einzelner Wert wird als int, mehrere Werte als array gespeichert.

#[Tries] — Anzahl der Retries angeben

Gibt die maximale Anzahl an Wiederholungsversuchen bei Fehlschlag an.
use Illuminate\Queue\Attributes\Tries;

#[Tries(5)]
class ProcessPayment implements ShouldQueue
{
    // ...
}

#[Timeout] — Timeout angeben

Gibt die maximale Laufzeit des Jobs (in Sekunden) an. Nach dieser Zeit wird der Job zwangsweise beendet.
use Illuminate\Queue\Attributes\Timeout;

#[Timeout(120)]
class GenerateReport implements ShouldQueue
{
    // ...
}

#[MaxExceptions] — Anzahl erlaubter Exceptions angeben

Wird die angegebene Anzahl an Exceptions überschritten, gilt der Job als fehlgeschlagen. Wird in Kombination mit #[Tries] genutzt.
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\Tries;

#[Tries(10)]
#[MaxExceptions(3)]
class ProcessWebhook implements ShouldQueue
{
    // ...
}

#[UniqueFor] — Eindeutigkeitsdauer angeben

Gibt die Sperrdauer (in Sekunden) an, während der ein Job nicht mehrfach ausgeführt wird. Nutzung in Kombination mit ShouldBeUnique.
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Queue\Attributes\UniqueFor;

#[UniqueFor(3600)]
class SyncUserData implements ShouldQueue, ShouldBeUnique
{
    // ...
}

#[DeleteWhenMissingModels] — bei fehlendem Modell löschen

Wenn das vom Job abhängige Eloquent-Modell nicht gefunden wird, wird der Job nicht als Fehler markiert, sondern gelöscht (übersprungen).
use Illuminate\Queue\Attributes\DeleteWhenMissingModels;

#[DeleteWhenMissingModels]
class SendOrderConfirmation implements ShouldQueue
{
    public function __construct(
        protected Order $order,
    ) {}

    public function handle(): void
    {
        // Existiert $order nicht, wird dieser Job gelöscht
    }
}

#[WithoutRelations] — Beziehungen ausschließen

Sorgt dafür, dass beim Serialisieren des Jobs die Model-Relationen nicht mitgeführt werden. So werden die an die Queue übertragenen Daten schlanker.
use Illuminate\Queue\Attributes\WithoutRelations;

#[WithoutRelations]
class ExportUser implements ShouldQueue
{
    public function __construct(
        protected User $user,
    ) {}
}

#[FailOnTimeout] — Timeout als Fehler werten

Registriert einen Timeout als Job-Fehlschlag (standardmäßig gilt ein Timeout nicht als Fehler).
use Illuminate\Queue\Attributes\FailOnTimeout;
use Illuminate\Queue\Attributes\Timeout;

#[Timeout(30)]
#[FailOnTimeout]
class ProcessLongTask implements ShouldQueue
{
    // ...
}

Mehrere Queue-Attribute kombinieren

Sie können diese Attribute kombinieren, um das Verhalten eines Jobs deklarativ zu konfigurieren.
use Illuminate\Queue\Attributes\Backoff;
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\DeleteWhenMissingModels;
use Illuminate\Queue\Attributes\FailOnTimeout;
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\Queue;
use Illuminate\Queue\Attributes\Timeout;
use Illuminate\Queue\Attributes\Tries;

#[Queue('payments')]
#[Connection('redis')]
#[Tries(3)]
#[Backoff(30, 60, 120)]
#[Timeout(60)]
#[MaxExceptions(2)]
#[DeleteWhenMissingModels]
class ProcessPayment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(
        protected Order $order,
    ) {}

    public function handle(PaymentService $payment): void
    {
        $payment->charge($this->order);
    }
}

Eloquent-bezogene Attribute

Die Eloquent-Modell-Attribute liegen im Namensraum Illuminate\Database\Eloquent\Attributes. Laravel 13 fügt zahlreiche Attribute hinzu.

#[ScopedBy] — Global Scope angeben

Über ein Attribut geben Sie die Global-Scope-Klasse an, die automatisch auf das Modell angewendet werden soll. Vererbung wird unterstützt; über das Flag IS_REPEATABLE können mehrere Scopes angegeben werden.
use Illuminate\Database\Eloquent\Attributes\ScopedBy;

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
    // Die Registrierung in booted() entfällt
}
Zum Zuweisen mehrerer Scopes wiederholen Sie das Attribut oder übergeben ein Array.
// Wiederholte Angabe (IS_REPEATABLE)
#[ScopedBy(ActiveScope::class)]
#[ScopedBy(VerifiedScope::class)]
class User extends Model
{
}

// Sammelangabe als Array
#[ScopedBy([ActiveScope::class, VerifiedScope::class])]
class User extends Model
{
}
Zum Vergleich die klassische booted()-Methode:
// Klassische Schreibweise
class User extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope(new ActiveScope);
        static::addGlobalScope(new VerifiedScope);
    }
}

#[ObservedBy] — Observer angeben

Über ein Attribut geben Sie die Observer-Klasse an, die dem Modell zugeordnet werden soll. Wie ScopedBy ist auch dieses Attribut IS_REPEATABLE.
use Illuminate\Database\Eloquent\Attributes\ObservedBy;

#[ObservedBy(UserObserver::class)]
class User extends Model
{
}
Auch mehrere Observer können angegeben werden.
#[ObservedBy(UserObserver::class)]
#[ObservedBy(AuditObserver::class)]
class User extends Model
{
}
Die klassische Registrierung im AppServiceProvider entfällt.
// Klassische Schreibweise (AppServiceProvider)
public function boot(): void
{
    User::observe(UserObserver::class);
}

#[UseEloquentBuilder] — eigenen Query Builder angeben

Über ein Attribut geben Sie den eigenen Eloquent-Builder an, den das Modell verwenden soll.
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;

#[UseEloquentBuilder(UserQueryBuilder::class)]
class User extends Model
{
}
namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class UserQueryBuilder extends Builder
{
    public function active(): static
    {
        return $this->where('active', true);
    }

    public function verified(): static
    {
        return $this->whereNotNull('email_verified_at');
    }
}
// Anwendungsbeispiel (typsichere Methodenaufrufe)
$users = User::query()->active()->verified()->get();

#[CollectedBy] — eigene Collection angeben

Über ein Attribut geben Sie die eigene Collection-Klasse an, die als Modell-Collection verwendet werden soll.
use Illuminate\Database\Eloquent\Attributes\CollectedBy;

#[CollectedBy(UserCollection::class)]
class User extends Model
{
}
namespace App\Collections;

use Illuminate\Database\Eloquent\Collection;

class UserCollection extends Collection
{
    public function admins(): static
    {
        return $this->filter(fn (User $user) => $user->is_admin);
    }

    public function active(): static
    {
        return $this->filter(fn (User $user) => $user->active);
    }
}

#[Table] — Tabelleneinstellungen gebündelt angeben

Sie können Tabellenname, Primärschlüssel, Timestamps und weitere tabellenbezogene Einstellungen mit einem einzigen Attribut angeben.
use Illuminate\Database\Eloquent\Attributes\Table;

#[Table(name: 'system_users', key: 'user_id', timestamps: false)]
class SystemUser extends Model
{
}
Die konfigurierbaren Optionen von Table sind:
ParameterEntsprechende EigenschaftBeschreibung
name$tableTabellenname
key$primaryKeySpaltenname des Primärschlüssels
keyType$keyTypeTyp des Primärschlüssels ('int', 'string' usw.)
incrementing$incrementingAuto-Increment des Primärschlüssels
timestamps$timestampsTimestamps aktiv/inaktiv
dateFormat$dateFormatDatumsformat

#[Scope] — Methode als lokalen Scope definieren

Sie können eine Methode ohne scope-Präfix als lokalen Eloquent-Scope kennzeichnen.
use Illuminate\Database\Eloquent\Attributes\Scope;

class User extends Model
{
    #[Scope]
    public function active(Builder $query): void
    {
        $query->where('active', true);
    }

    #[Scope]
    public function verified(Builder $query): void
    {
        $query->whereNotNull('email_verified_at');
    }
}
// Bisher musste der Methodenname den Präfix „scope" tragen
// public function scopeActive(Builder $query): void

// Mit Attribut wird der Methodenname direkt zum Scope-Namen
User::query()->active()->verified()->get();

#[UseFactory] — Factory-Klasse angeben

Über ein Attribut geben Sie die eigene Factory-Klasse an, die das Modell verwenden soll.
use Illuminate\Database\Eloquent\Attributes\UseFactory;

#[UseFactory(UserFactory::class)]
class User extends Model
{
}

Weitere Eloquent-Attribute

AttributBeschreibung
#[Fillable(...$attributes)]Erlaubte Spalten für Mass Assignment angeben
#[Guarded(...$attributes)]Für Mass Assignment geschützte Spalten angeben
#[Unguarded]Mass-Assignment-Schutz deaktivieren
#[Hidden(...$attributes)]Beim Serialisieren auszuschließende Spalten angeben
#[Visible(...$attributes)]Beim Serialisieren einzuschließende Spalten angeben
#[Appends(...$attributes)]Beim Serialisieren zu ergänzende Accessoren angeben
#[Touches(...$relations)]Beziehungen angeben, deren updated_at bei Änderungen aktualisiert wird
#[WithoutTimestamps]Timestamps deaktivieren
#[WithoutIncrementing]Auto-Increment des Primärschlüssels deaktivieren
#[DateFormat(format: '...')]Datumsformat angeben
#[UsePolicy(policyClass: '...')]Zugehörige Policy-Klasse angeben
#[UseResource(resourceClass: '...')]Zugehörige API-Resource-Klasse angeben
#[UseResourceCollection(resourceCollectionClass: '...')]Zugehörige Resource-Collection-Klasse angeben

Enum-Unterstützung (neu in v13.2.0)

Ab v13.2.0 akzeptieren #[Queue] und #[Connection] Enums. Damit können Sie statt String-Literalen typsichere PHP-Enums für Queues und Verbindungen verwenden.
// Enum-Definition für Queue-Namen
enum Queue: string
{
    case Default = 'default';
    case High = 'high';
    case Low = 'low';
    case Emails = 'emails';
    case Orders = 'orders';
}

// Enum-Definition für Verbindungen
enum Connection: string
{
    case Redis = 'redis';
    case Sqs = 'sqs';
    case Database = 'database';
    case Sync = 'sync';
}
use Illuminate\Queue\Attributes\Queue;
use Illuminate\Queue\Attributes\Connection;

// Typsichere Angabe mit Enum
#[Queue(Queue::Orders)]
#[Connection(Connection::Redis)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
Mit Enums vermeiden Sie Tippfehler bei Queue- und Connection-Namen und können IDE-Vervollständigung nutzen. Sehr praktisch, um Queue- und Connection-Namen anwendungsweit an einer Stelle zu verwalten.

Vergleich mit klassischen Klasseneigenschaften

Vorteile der Attribute

  • Deklarativ — das Verhalten des Jobs ist sofort am Anfang der Klasse ersichtlich
  • Typsicher — mit Enums profitieren Sie von IDE-Vervollständigung und Typprüfung
  • Vererbungsfreundlich — Attribute der Elternklasse lassen sich in Unterklassen überschreiben
  • Weniger Code — Property-Deklarationen und Method-Overrides entfallen

Nachteile der Attribute

  • Keine dynamischen Werte — die Argumente sind Compile-Time-Konstanten; Variablen oder Configwerte sind nicht möglich
  • Einarbeitung nötig — im Team kann Übung mit der Attribut-Syntax von PHP 8 erforderlich sein

Wenn dynamische Werte gebraucht werden

Sollen die Werte zur Laufzeit bestimmt werden, verwenden Sie weiterhin Methodenüberschreibungen.
class ProcessOrder implements ShouldQueue
{
    // Dynamisches Backoff über eine Methode definieren
    public function backoff(): array
    {
        return [
            config('queue.backoff.first'),
            config('queue.backoff.second'),
        ];
    }
}
Attribute werden zur PHP-Compile-Time ausgewertet. Laufzeitwerte wie config() oder env() können nicht genutzt werden. Für dynamische Konfigurationen verwenden Sie weiterhin Klasseneigenschaften oder Methoden.

Interner Aufbau

Laravel liest Attribute intern über die Reflection API aus. Beim Dispatchen eines Jobs erkennt der Trait ReadsQueueAttributes (Bestandteil von InteractsWithQueue) die Attribute per Reflection und setzt die passenden Eigenschaften.
// Vereinfachte interne Vorstellung
$reflection = new ReflectionClass($job);
$attributes = $reflection->getAttributes(Queue::class);

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    $job->queue = $instance->queue instanceof UnitEnum
        ? $instance->queue->value
        : $instance->queue;
}
Eloquent-Modell-Attribute werden analog dazu — etwa im Zeitpunkt von Model::booted() — per Reflection ausgelesen.

Nächste Schritte

Mittelstufe: Queues und Jobs

Lernen Sie die grundlegende Nutzung des Laravel-Queue-Systems.

PHP Reflection API

Detaillierte Erläuterung der Reflection API, mit der Laravel Attribute ausliest.
Zuletzt geändert am 13. Juli 2026