> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Attributi PHP

> Come utilizzare gli attributi PHP introdotti e potenziati in Laravel 13 per configurare in modo più dichiarativo job e modelli.

## Cosa sono gli attributi PHP

Gli attributi PHP sono una sintassi nativa di metadati introdotta con PHP 8.0. Permettono di applicare meta-informazioni a classi, metodi, proprietà, funzioni ecc. nella forma `#[AttributeName]`.

Laravel adotta attivamente gli attributi PHP nel framework, e ti permette di configurare in modo dichiarativo job e modelli Eloquent. In Laravel 13 (v13.2.0) gli attributi per le queue accettano enum. Al posto delle proprietà di classe o degli override di metodi puoi scrivere codice più leggibile e conciso.

```php theme={null}
// scrittura tradizionale
class ProcessOrder implements ShouldQueue
{
    public string $queue = 'orders';
    public string $connection = 'redis';
    public int $tries = 3;
    public array $backoff = [30, 60, 120];
}

// scrittura con attributi
#[Queue('orders')]
#[Connection('redis')]
#[Tries(3)]
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
}
```

<Tip>
  Gli attributi sono disponibili da PHP 8.0. Laravel 13 richiede PHP 8.3 o superiore, quindi puoi usare gli attributi in tutti gli ambienti.
</Tip>

## Attributi per le code

Gli attributi relativi ai job in coda si trovano tutti nel namespace `Illuminate\Queue\Attributes`.

### `#[Queue]` — indicare il nome della coda

Indica il nome della coda di default in cui il job viene inviato.

```php theme={null}
use Illuminate\Queue\Attributes\Queue;

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

    public function handle(): void
    {
        // ...
    }
}
```

Da v13.2.0 puoi passare anche un enum al posto della stringa.

```php theme={null}
enum QueueName: string
{
    case Emails = 'emails';
    case Orders = 'orders';
    case Notifications = 'notifications';
}

#[Queue(QueueName::Emails)]
class SendWelcomeEmail implements ShouldQueue
{
    // ...
}
```

<Info>
  L'attributo `#[Queue]` è impostato con target `Attribute::TARGET_CLASS`, quindi è applicabile solo alle classi.
</Info>

### `#[Connection]` — indicare la connessione

Indica la connection di coda di default usata dal job.

```php theme={null}
use Illuminate\Queue\Attributes\Connection;

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

    public function handle(): void
    {
        // ...
    }
}
```

Anche qui puoi usare un enum.

```php theme={null}
enum QueueConnection: string
{
    case Redis = 'redis';
    case Sqs = 'sqs';
    case Database = 'database';
}

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

### `#[Backoff]` — tempo di backoff per i retry

Indica il tempo di attesa (in secondi) prima di ritentare quando il job fallisce. Passando più valori puoi impostare un tempo diverso per ogni retry (supporta argomenti variadic).

```php theme={null}
use Illuminate\Queue\Attributes\Backoff;

// attesa fissa (60 secondi comune a tutti i retry)
#[Backoff(60)]
class SendEmail implements ShouldQueue
{
    // ...
}

// attese diverse per ogni retry (exponential backoff)
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

Guardando l'implementazione della classe `Backoff` è progettata per ricevere argomenti variadic.

```php theme={null}
// implementazione di 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;
    }
}
```

Un singolo valore viene memorizzato come `int`, più valori come `array`.

### `#[Tries]` — numero di retry

Indica il numero massimo di retry quando il job fallisce.

```php theme={null}
use Illuminate\Queue\Attributes\Tries;

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

### `#[Timeout]` — timeout

Indica il tempo massimo di esecuzione del job (in secondi). Superata questa soglia il job viene terminato forzatamente.

```php theme={null}
use Illuminate\Queue\Attributes\Timeout;

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

### `#[MaxExceptions]` — numero massimo di eccezioni tollerate

Se avvengono più eccezioni del numero indicato, il job viene considerato fallito. Da combinare con `#[Tries]`.

```php theme={null}
use Illuminate\Queue\Attributes\MaxExceptions;
use Illuminate\Queue\Attributes\Tries;

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

### `#[UniqueFor]` — periodo di unicità

Indica il periodo di lock (in secondi) per evitare esecuzioni duplicate. Da usare con `ShouldBeUnique`.

```php theme={null}
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Queue\Attributes\UniqueFor;

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

### `#[DeleteWhenMissingModels]` — cancella se il modello non esiste

Se un modello Eloquent da cui dipende il job non viene trovato, il job viene cancellato (saltato) anziché fallito.

```php theme={null}
use Illuminate\Queue\Attributes\DeleteWhenMissingModels;

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

    public function handle(): void
    {
        // se $order non esiste, questo job viene cancellato
    }
}
```

### `#[WithoutRelations]` — escludere le relation

Fa in modo che, al momento della serializzazione, le relation del modello non vengano incluse. Alleggerisce i dati inviati in coda.

```php theme={null}
use Illuminate\Queue\Attributes\WithoutRelations;

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

### `#[FailOnTimeout]` — timeout come fallimento

Registra il job come fallito quando avviene un timeout (di default il timeout non viene registrato come fallimento).

```php theme={null}
use Illuminate\Queue\Attributes\FailOnTimeout;
use Illuminate\Queue\Attributes\Timeout;

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

## Combinare più attributi delle code

Combinando questi attributi configuri in modo dichiarativo il comportamento del job.

```php theme={null}
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);
    }
}
```

## Attributi per Eloquent

Gli attributi per i modelli Eloquent si trovano nel namespace `Illuminate\Database\Eloquent\Attributes`. In Laravel 13 ne sono stati aggiunti molti.

### `#[ScopedBy]` — indicare un global scope

Indica con un attributo la classe di global scope da applicare automaticamente al modello. Supporta l'ereditarietà; con il flag `IS_REPEATABLE` puoi indicare più scope.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\ScopedBy;

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
    // non serve più registrare lo scope in booted()
}
```

Per più scope puoi ripetere l'attributo o passare un array.

```php theme={null}
// specifica ripetuta (supporta IS_REPEATABLE)
#[ScopedBy(ActiveScope::class)]
#[ScopedBy(VerifiedScope::class)]
class User extends Model
{
}

// specifica raggruppata in array
#[ScopedBy([ActiveScope::class, VerifiedScope::class])]
class User extends Model
{
}
```

Confronto con il metodo `booted()` tradizionale.

```php theme={null}
// scrittura tradizionale
class User extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope(new ActiveScope);
        static::addGlobalScope(new VerifiedScope);
    }
}
```

### `#[ObservedBy]` — indicare un observer

Indica con un attributo la classe observer associata al modello. Come `ScopedBy`, è `IS_REPEATABLE`.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\ObservedBy;

#[ObservedBy(UserObserver::class)]
class User extends Model
{
}
```

Puoi indicare più observer.

```php theme={null}
#[ObservedBy(UserObserver::class)]
#[ObservedBy(AuditObserver::class)]
class User extends Model
{
}
```

Non serve più la registrazione in `AppServiceProvider`.

```php theme={null}
// registrazione tradizionale (AppServiceProvider)
public function boot(): void
{
    User::observe(UserObserver::class);
}
```

### `#[UseEloquentBuilder]` — indicare un query builder custom

Indica con un attributo l'Eloquent builder personalizzato usato dal modello.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;

#[UseEloquentBuilder(UserQueryBuilder::class)]
class User extends Model
{
}
```

```php theme={null}
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');
    }
}
```

```php theme={null}
// utilizzo (chiamata dei metodi custom con type safety)
$users = User::query()->active()->verified()->get();
```

### `#[CollectedBy]` — indicare una collection custom

Indica con un attributo la classe di collection personalizzata usata per il modello.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\CollectedBy;

#[CollectedBy(UserCollection::class)]
class User extends Model
{
}
```

```php theme={null}
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]` — configurazione tabella in un attributo

Puoi indicare in un unico attributo più impostazioni della tabella: nome, primary key, timestamps.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\Table;

#[Table(name: 'system_users', key: 'user_id', timestamps: false)]
class SystemUser extends Model
{
}
```

Opzioni configurabili con l'attributo `Table`:

| Parametro      | Proprietà corrispondente | Descrizione                                        |
| -------------- | ------------------------ | -------------------------------------------------- |
| `name`         | `$table`                 | Nome della tabella                                 |
| `key`          | `$primaryKey`            | Nome della colonna della primary key               |
| `keyType`      | `$keyType`               | Tipo della primary key (`'int'`, `'string'`, ecc.) |
| `incrementing` | `$incrementing`          | Autoincremento della primary key                   |
| `timestamps`   | `$timestamps`            | Abilitazione dei timestamps                        |
| `dateFormat`   | `$dateFormat`            | Formato delle date                                 |

### `#[Scope]` — definire un metodo come local scope

Puoi definire un metodo come local scope Eloquent senza prefisso `scope`.

```php theme={null}
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');
    }
}
```

```php theme={null}
// in passato serviva il prefisso "scope" nel nome
// public function scopeActive(Builder $query): void

// con l'attributo il nome del metodo è direttamente il nome dello scope
User::query()->active()->verified()->get();
```

### `#[UseFactory]` — indicare la classe factory

Indica con un attributo la classe factory personalizzata del modello.

```php theme={null}
use Illuminate\Database\Eloquent\Attributes\UseFactory;

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

### Altri attributi Eloquent

| Attributo                                                  | Descrizione                                                 |
| ---------------------------------------------------------- | ----------------------------------------------------------- |
| `#[Fillable(...$attributes)]`                              | Indica le colonne consentite dal mass assignment            |
| `#[Guarded(...$attributes)]`                               | Indica le colonne protette dal mass assignment              |
| `#[Unguarded]`                                             | Disabilita la protezione del mass assignment                |
| `#[Hidden(...$attributes)]`                                | Indica le colonne da escludere in serializzazione           |
| `#[Visible(...$attributes)]`                               | Indica le colonne da includere in serializzazione           |
| `#[Appends(...$attributes)]`                               | Indica gli accessor da aggiungere in serializzazione        |
| `#[Touches(...$relations)]`                                | Indica le relation di cui aggiornare `updated_at` in update |
| `#[WithoutTimestamps]`                                     | Disabilita i timestamp                                      |
| `#[WithoutIncrementing]`                                   | Disabilita l'autoincremento della primary key               |
| `#[DateFormat(format: '...')]`                             | Indica il formato delle date                                |
| `#[UsePolicy(policyClass: '...')]`                         | Indica la policy class collegata                            |
| `#[UseResource(resourceClass: '...')]`                     | Indica la resource API collegata                            |
| `#[UseResourceCollection(resourceCollectionClass: '...')]` | Indica la resource collection collegata                     |

## Supporto agli enum (aggiunto in v13.2.0)

In v13.2.0 `#[Queue]` e `#[Connection]` accettano enum. Al posto delle stringhe letterali puoi indicare queue e connection in modo type-safe con enum PHP.

```php theme={null}
// definizione enum del nome coda
enum Queue: string
{
    case Default = 'default';
    case High = 'high';
    case Low = 'low';
    case Emails = 'emails';
    case Orders = 'orders';
}

// definizione enum della connection
enum Connection: string
{
    case Redis = 'redis';
    case Sqs = 'sqs';
    case Database = 'database';
    case Sync = 'sync';
}
```

```php theme={null}
use Illuminate\Queue\Attributes\Queue;
use Illuminate\Queue\Attributes\Connection;

// specifica type-safe con enum
#[Queue(Queue::Orders)]
#[Connection(Connection::Redis)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

<Tip>
  Con gli enum eviti errori di battitura in nomi di code e connection e sfrutti l'autocompletamento dell'IDE. È utile per gestire in modo centralizzato nomi di coda e connection nell'intera applicazione.
</Tip>

## Confronto con le proprietà di classe tradizionali

### Vantaggi degli attributi

* **Dichiarativi** — guardando l'inizio della classe capisci a colpo d'occhio il comportamento del job
* **Type-safe** — con gli enum ottieni autocompletamento e type check dell'IDE
* **Buoni con l'ereditarietà** — puoi sovrascrivere in una classe figlia gli attributi della classe padre
* **Meno codice** — niente dichiarazioni di proprietà o override di metodi

### Svantaggi

* **Non puoi impostare valori dinamici** — gli argomenti degli attributi sono solo costanti a compile time: variabili o valori di config non funzionano
* **Serve familiarità** — a volte il team ha bisogno di prendere confidenza con la sintassi degli attributi PHP 8

### Se ti servono valori dinamici

Se vuoi decidere i valori a runtime, usa il tradizionale override di metodo.

```php theme={null}
class ProcessOrder implements ShouldQueue
{
    // backoff dinamico definito come metodo
    public function backoff(): array
    {
        return [
            config('queue.backoff.first'),
            config('queue.backoff.second'),
        ];
    }
}
```

<Warning>
  Gli attributi vengono analizzati al momento della compilazione di PHP. Non puoi usare valori a runtime come `config()` o `env()`. Se ti servono impostazioni dinamiche, continua a usare proprietà o metodi di classe.
</Warning>

## Meccanismo di implementazione

Internamente Laravel usa la Reflection API per leggere gli attributi. Quando il queue worker fa dispatch del job, il trait `ReadsQueueAttributes` (incluso in `InteractsWithQueue`) individua gli attributi via reflection e imposta i valori sulle proprietà corrispondenti.

```php theme={null}
// idea della lettura interna (semplificata)
$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;
}
```

Anche gli attributi dei modelli Eloquent vengono letti in modo analogo, al momento equivalente a `Model::booted()`.

## Prossimi passi

<Columns cols={2}>
  <Card title="Intermedio: code e job" icon="layer-group" href="/it/queues">
    Impara l'uso di base del sistema code di Laravel.
  </Card>

  <Card title="PHP Reflection API" icon="magnifying-glass" href="/it/advanced/php-reflection">
    Approfondisci il meccanismo della Reflection API usata da Laravel per leggere gli attributi.
  </Card>
</Columns>


## Related topics

- [PHP Reflection API](/it/advanced/php-reflection.md)
- [Aggiornamenti Laravel di marzo 2026](/it/blog/changelog/202603.md)
- [Riepilogo delle novità di Laravel 13](/it/blog/laravel-13-new-features.md)
- [Eloquent Observers ed eventi del modello](/it/advanced/eloquent-observers.md)
- [Driver Amazon Bedrock per Laravel AI SDK](/it/packages/laravel-amazon-bedrock.md)
