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

# Atributos de PHP

> Cómo usar los atributos de PHP introducidos y reforzados en Laravel 13 para declarar de forma más expresiva la configuración de jobs y modelos.

## Qué son los atributos de PHP

Los atributos de PHP (PHP Attributes) son una sintaxis nativa de metadatos introducida en PHP 8.0. Permiten asignar información meta a clases, métodos, propiedades o funciones con la forma `#[AttributeName]`.

Laravel adopta ampliamente los atributos de PHP en el framework y permite declarar de forma más expresiva la configuración de jobs y modelos Eloquent. En Laravel 13 (v13.2.0), los atributos de cola aceptan enums. En lugar de propiedades de clase o de sobrescribir métodos, puedes usar atributos para escribir código más legible y conciso.

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

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

<Tip>
  Los atributos están disponibles desde PHP 8.0. Como Laravel 13 requiere PHP 8.3 o superior, puedes usarlos en cualquier entorno soportado.
</Tip>

## Atributos relacionados con colas

Todos los atributos relacionados con jobs están en el namespace `Illuminate\Queue\Attributes`.

### `#[Queue]` — nombre de la cola

Indica el nombre por defecto de la cola a la que se envía el job.

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

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

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

Desde v13.2.0 también puedes pasar un enum en lugar de una cadena.

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

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

<Info>
  El atributo `#[Queue]` está declarado con `Attribute::TARGET_CLASS`, por lo que solo se puede aplicar a clases.
</Info>

### `#[Connection]` — indicar la conexión

Indica la conexión de cola por defecto que usará el job.

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

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

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

También admite enums.

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

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

### `#[Backoff]` — tiempo de espera entre reintentos

Indica el tiempo de espera (en segundos) hasta el siguiente reintento cuando falla el job. Aceptando varios valores, puedes configurar tiempos distintos por reintento (variadic).

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

// Tiempo fijo para todos los reintentos (60 s)
#[Backoff(60)]
class SendEmail implements ShouldQueue
{
    // ...
}

// Diferente por reintento (backoff exponencial)
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

Al ver la implementación de `Backoff`, se aprecia que está diseñado para aceptar argumentos variádicos.

```php theme={null}
// Implementación de 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;
    }
}
```

Si hay un solo valor, se guarda como `int`; si hay varios, como `array`.

### `#[Tries]` — número de reintentos

Indica el número máximo de reintentos al fallar el job.

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

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

### `#[Timeout]` — indicar el timeout

Indica el tiempo máximo de ejecución (en segundos) del job. Si se supera, se aborta forzosamente.

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

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

### `#[MaxExceptions]` — número máximo de excepciones toleradas

Considera fallido el job si ocurren más excepciones de las indicadas. Se usa junto a `#[Tries]`.

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

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

### `#[UniqueFor]` — periodo de unicidad

Indica el periodo de bloqueo (en segundos) para evitar la ejecución duplicada del job. Se combina con `ShouldBeUnique`.

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

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

### `#[DeleteWhenMissingModels]` — eliminar cuando no exista el modelo

Si el modelo Eloquent del que depende el job no existe, se trata como eliminado (se salta) en lugar de fallido.

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

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

    public function handle(): void
    {
        // Si $order no existe, este job se elimina
    }
}
```

### `#[WithoutRelations]` — excluir relaciones

Evita incluir las relaciones del modelo al serializar el job. Reduce el peso de los datos enviados a la cola.

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

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

### `#[FailOnTimeout]` — marcar como fallo al agotarse el tiempo

Registra el timeout como fallo (por defecto no se registra como tal).

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

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

## Combinar varios atributos de cola

Puedes combinar estos atributos para declarar de forma expresiva el comportamiento 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);
    }
}
```

## Atributos relacionados con Eloquent

Los atributos para modelos Eloquent están en el namespace `Illuminate\Database\Eloquent\Attributes`. Laravel 13 añade muchos atributos.

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

Indica mediante atributo la clase de scope global que se aplica automáticamente al modelo. Admite herencia y, gracias al flag `IS_REPEATABLE`, varios scopes.

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

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
    // Ya no hace falta registrar el scope en booted()
}
```

Para varios scopes, repite el atributo o pásalos como array.

```php theme={null}
// Repitiendo (compatible con IS_REPEATABLE)
#[ScopedBy(ActiveScope::class)]
#[ScopedBy(VerifiedScope::class)]
class User extends Model
{
}

// En un solo array
#[ScopedBy([ActiveScope::class, VerifiedScope::class])]
class User extends Model
{
}
```

Comparación con la forma tradicional en `booted()`.

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

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

Indica mediante atributo la clase observer asociada al modelo. También es `IS_REPEATABLE`, como `ScopedBy`.

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

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

Puedes indicar varios observers.

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

Ya no es necesario el registro tradicional en `AppServiceProvider`.

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

### `#[UseEloquentBuilder]` — indicar un query builder personalizado

Indica mediante atributo el Eloquent Builder personalizado que usará el modelo.

```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}
// Uso (puedes llamar a los métodos personalizados con seguridad de tipos)
$users = User::query()->active()->verified()->get();
```

### `#[CollectedBy]` — indicar una collection personalizada

Indica mediante atributo la clase de collection personalizada que representa las colecciones del modelo.

```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]` — configuración de tabla en un solo atributo

Indica en un único atributo varios ajustes relacionados con la tabla: nombre, clave primaria, timestamps, etc.

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

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

Las opciones que puedes configurar con el atributo `Table`:

| Parámetro      | Propiedad equivalente | Descripción                                       |
| -------------- | --------------------- | ------------------------------------------------- |
| `name`         | `$table`              | Nombre de la tabla.                               |
| `key`          | `$primaryKey`         | Nombre de la columna de clave primaria.           |
| `keyType`      | `$keyType`            | Tipo de la clave primaria (`'int'`, `'string'`…). |
| `incrementing` | `$incrementing`       | Si la clave primaria es autoincremental.          |
| `timestamps`   | `$timestamps`         | Activar/desactivar timestamps.                    |
| `dateFormat`   | `$dateFormat`         | Formato de fecha.                                 |

### `#[Scope]` — definir un método como local scope

Permite declarar un método como local scope de Eloquent sin necesidad del prefijo `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}
// Antes se necesitaba el prefijo "scope"
// public function scopeActive(Builder $query): void

// Con el atributo, el nombre del método es directamente el del scope
User::query()->active()->verified()->get();
```

### `#[UseFactory]` — indicar la clase factory

Indica mediante atributo la clase factory personalizada que usará el modelo.

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

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

### Otros atributos de Eloquent

| Atributo                                                   | Descripción                                             |
| ---------------------------------------------------------- | ------------------------------------------------------- |
| `#[Fillable(...$attributes)]`                              | Columnas permitidas en asignación masiva.               |
| `#[Guarded(...$attributes)]`                               | Columnas protegidas frente a asignación masiva.         |
| `#[Unguarded]`                                             | Desactiva la protección de asignación masiva.           |
| `#[Hidden(...$attributes)]`                                | Columnas excluidas al serializar.                       |
| `#[Visible(...$attributes)]`                               | Columnas incluidas al serializar.                       |
| `#[Appends(...$attributes)]`                               | Accesores que se añaden al serializar.                  |
| `#[Touches(...$relations)]`                                | Relaciones cuyo `updated_at` se actualiza al modificar. |
| `#[WithoutTimestamps]`                                     | Desactiva los timestamps.                               |
| `#[WithoutIncrementing]`                                   | Desactiva el auto-incremento de la clave primaria.      |
| `#[DateFormat(format: '...')]`                             | Indica el formato de fecha.                             |
| `#[UsePolicy(policyClass: '...')]`                         | Indica la clase policy asociada.                        |
| `#[UseResource(resourceClass: '...')]`                     | Indica la clase resource API asociada.                  |
| `#[UseResourceCollection(resourceCollectionClass: '...')]` | Indica la clase de resource collection asociada.        |

## Soporte de enums (añadido en v13.2.0)

En v13.2.0, `#[Queue]` y `#[Connection]` aceptan enums. Así puedes indicar cola y conexión de forma tipada, en lugar de con literales string.

```php theme={null}
// Definición del enum de cola
enum Queue: string
{
    case Default = 'default';
    case High = 'high';
    case Low = 'low';
    case Emails = 'emails';
    case Orders = 'orders';
}

// Definición del enum de conexión
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;

// Especificación tipada con enums
#[Queue(Queue::Orders)]
#[Connection(Connection::Redis)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

<Tip>
  Con enums evitas errores tipográficos en nombres de cola o conexión y aprovechas el autocompletado del IDE. Es muy útil para gestionar de forma centralizada los nombres de cola y conexión en toda la aplicación.
</Tip>

## Comparación con las propiedades de clase tradicionales

### Ventajas de los atributos

* **Declarativos** — con solo mirar el encabezado de la clase entiendes el comportamiento del job.
* **Tipados** — al usar enums, tienes autocompletado y comprobación de tipos.
* **Compatibles con la herencia** — puedes sobrescribir en la subclase los atributos de la clase padre.
* **Menos código** — no hacen falta declaraciones de propiedades ni sobrescribir métodos.

### Desventajas de los atributos

* **No se puede fijar un valor dinámico** — los argumentos son constantes de compilación. No aceptan variables ni valores de configuración.
* **Requiere costumbre** — puede que tu equipo necesite tiempo para acostumbrarse a la sintaxis de PHP 8.

### Cuando necesitas valores dinámicos

Si necesitas decidir el valor en tiempo de ejecución, sigue usando la sobrescritura de métodos.

```php theme={null}
class ProcessOrder implements ShouldQueue
{
    // Backoff dinámico definido en un método
    public function backoff(): array
    {
        return [
            config('queue.backoff.first'),
            config('queue.backoff.second'),
        ];
    }
}
```

<Warning>
  Los atributos se analizan en tiempo de compilación de PHP. No puedes usar valores en tiempo de ejecución como `config()` o `env()`. Si necesitas configuración dinámica, sigue empleando propiedades o métodos.
</Warning>

## Cómo se implementa

Internamente, Laravel usa la Reflection API para leer los atributos. Cuando el worker de la cola despacha un job, el trait `ReadsQueueAttributes` (incluido en `InteractsWithQueue`) los detecta mediante reflexión y les asigna los valores a las propiedades correspondientes.

```php theme={null}
// Imagen simplificada de la lectura interna
$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;
}
```

Los atributos de los modelos Eloquent se leen por reflexión de forma análoga, aproximadamente en el momento de `Model::booted()`.

## Próximos pasos

<Columns cols={2}>
  <Card title="Intermedio: Colas y jobs" icon="layer-group" href="/es/queues">
    Aprende el uso básico del sistema de colas de Laravel.
  </Card>

  <Card title="PHP Reflection API" icon="magnifying-glass" href="/es/advanced/php-reflection">
    Explica en detalle cómo Laravel usa la Reflection API para leer los atributos.
  </Card>
</Columns>


## Related topics

- [PHP Reflection API](/es/advanced/php-reflection.md)
- [Actualización de Laravel — Marzo de 2026](/es/blog/changelog/202603.md)
- [Resumen de las novedades de Laravel 13](/es/blog/laravel-13-new-features.md)
- [Envío de correo](/es/mail.md)
- [Laravel AI SDK](/es/ai-sdk.md)
