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

# PHP 属性

> 讲解如何使用 Laravel 13 引入并强化的 PHP 属性，以更声明式的方式配置 Job 与 Model。

## 什么是 PHP 属性

PHP 属性（PHP Attributes）是 PHP 8.0 引入的原生元数据语法。可以对类、方法、属性、函数等以 `#[AttributeName]` 形式附加元信息。

Laravel 在框架内部积极采用 PHP 属性，可以以声明式的方式配置 Job 与 Eloquent Model。Laravel 13（v13.2.0）中队列属性还开始接受 enum。相较于以往通过类属性或方法覆写来设置，使用属性可以写出更易读、更简洁的代码。

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

// 使用属性的写法
#[Queue('orders')]
#[Connection('redis')]
#[Tries(3)]
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
}
```

<Tip>
  属性在 PHP 8.0 及以上可用。Laravel 13 要求 PHP 8.3 及以上，因此在所有环境中都能使用属性。
</Tip>

## 队列相关属性

队列 Job 相关的属性都位于 `Illuminate\Queue\Attributes` 命名空间。

### `#[Queue]` — 指定队列名

指定 Job 派发的默认队列名。

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

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

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

从 v13.2.0 起，除了字符串也可以传入 enum。

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

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

<Info>
  `#[Queue]` 属性的 target 被设置为 `Attribute::TARGET_CLASS`，因此只能用在类上。
</Info>

### `#[Connection]` — 指定连接

指定 Job 使用的默认队列连接。

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

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

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

同样也支持 enum。

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

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

### `#[Backoff]` — 指定重试的退避时间

指定 Job 失败后重试前的等待时间（秒）。可传多个值为不同次重试指定不同等待时间（支持可变参数）。

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

// 固定等待时间（所有重试共 60 秒）
#[Backoff(60)]
class SendEmail implements ShouldQueue
{
    // ...
}

// 每次重试不同的等待时间（指数退避）
#[Backoff(30, 60, 120)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

看 `Backoff` 类的实现，它接收可变参数。

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

单值时保存为 `int`，多值时保存为 `array`。

### `#[Tries]` — 指定重试次数

指定 Job 失败时的最大重试次数。

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

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

### `#[Timeout]` — 指定超时时间

指定 Job 的最大执行时间（秒），超过则会被强制终止。

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

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

### `#[MaxExceptions]` — 指定允许的异常次数

发生指定次数以上的异常时，将 Job 视为失败。通常与 `#[Tries]` 搭配使用。

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

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

### `#[UniqueFor]` — 指定唯一周期

指定阻止 Job 重复执行的锁定周期（秒）。与 `ShouldBeUnique` 一起使用。

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

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

### `#[DeleteWhenMissingModels]` — 模型不存在时删除

当 Job 依赖的 Eloquent 模型不存在时，将该 Job 视为删除（跳过）而不是失败。

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

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

    public function handle(): void
    {
        // 当 $order 不存在时，该 Job 会被删除
    }
}
```

### `#[WithoutRelations]` — 排除关联

在 Job 序列化时不包含模型的关联，可以让入队数据更小。

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

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

### `#[FailOnTimeout]` — 超时视为失败

发生超时时把 Job 记录为失败（默认情况下超时不会记录为失败）。

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

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

## 组合多个队列属性

将这些属性组合可以以声明方式配置 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);
    }
}
```

## Eloquent 相关属性

Eloquent 模型属性位于 `Illuminate\Database\Eloquent\Attributes` 命名空间。Laravel 13 中新增了大量属性。

### `#[ScopedBy]` — 指定全局作用域

以属性形式指定要自动应用到模型上的全局作用域类。支持继承，通过 `IS_REPEATABLE` 标志可以指定多个作用域。

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

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
    // 无需在 booted() 中注册作用域
}
```

要绑定多个作用域时，可重复使用属性或以数组形式传入。

```php theme={null}
// 重复指定（IS_REPEATABLE）
#[ScopedBy(ActiveScope::class)]
#[ScopedBy(VerifiedScope::class)]
class User extends Model
{
}

// 用数组一次指定
#[ScopedBy([ActiveScope::class, VerifiedScope::class])]
class User extends Model
{
}
```

与传统的 `booted()` 方法对比。

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

### `#[ObservedBy]` — 指定 Observer

以属性形式指定模型关联的 Observer 类。与 `ScopedBy` 一样是 `IS_REPEATABLE`。

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

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

也可以指定多个 Observer。

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

无需再在 `AppServiceProvider` 中注册。

```php theme={null}
// 传统写法（AppServiceProvider）
public function boot(): void
{
    User::observe(UserObserver::class);
}
```

### `#[UseEloquentBuilder]` — 指定自定义 Query Builder

以属性形式指定模型所使用的自定义 Eloquent Builder。

```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}
// 使用示例（可以类型安全地调用自定义方法）
$users = User::query()->active()->verified()->get();
```

### `#[CollectedBy]` — 指定自定义 Collection

以属性形式指定模型作为集合时使用的自定义 Collection 类。

```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]` — 一次指定表相关配置

在一个属性中指定表名、主键、时间戳等多个表相关配置。

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

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

`Table` 属性可配置的选项如下。

| 参数             | 对应属性            | 说明                         |
| -------------- | --------------- | -------------------------- |
| `name`         | `$table`        | 表名                         |
| `key`          | `$primaryKey`   | 主键列名                       |
| `keyType`      | `$keyType`      | 主键类型（`'int'`、`'string'` 等） |
| `incrementing` | `$incrementing` | 主键是否自增                     |
| `timestamps`   | `$timestamps`   | 是否启用时间戳                    |
| `dateFormat`   | `$dateFormat`   | 日期格式                       |

### `#[Scope]` — 将方法定义为本地作用域

可以把没有 `scope` 前缀的方法定义为 Eloquent 本地作用域。

```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}
// 传统写法方法名需带「scope」前缀
// public function scopeActive(Builder $query): void

// 使用属性后方法名直接作为作用域名
User::query()->active()->verified()->get();
```

### `#[UseFactory]` — 指定 Factory 类

以属性形式指定模型使用的自定义 Factory 类。

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

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

### 其他 Eloquent 属性

| 属性                                                         | 说明                          |
| ---------------------------------------------------------- | --------------------------- |
| `#[Fillable(...$attributes)]`                              | 指定批量赋值允许的列                  |
| `#[Guarded(...$attributes)]`                               | 指定批量赋值保护的列                  |
| `#[Unguarded]`                                             | 禁用批量赋值保护                    |
| `#[Hidden(...$attributes)]`                                | 指定序列化时排除的列                  |
| `#[Visible(...$attributes)]`                               | 指定序列化时包含的列                  |
| `#[Appends(...$attributes)]`                               | 指定序列化时追加的 accessor          |
| `#[Touches(...$relations)]`                                | 指定更新时同步更新 `updated_at` 的关联  |
| `#[WithoutTimestamps]`                                     | 禁用时间戳                       |
| `#[WithoutIncrementing]`                                   | 禁用主键自增                      |
| `#[DateFormat(format: '...')]`                             | 指定日期格式                      |
| `#[UsePolicy(policyClass: '...')]`                         | 指定关联的 Policy 类              |
| `#[UseResource(resourceClass: '...')]`                     | 指定关联的 API Resource 类        |
| `#[UseResourceCollection(resourceCollectionClass: '...')]` | 指定关联的 Resource Collection 类 |

## Enum 支持（v13.2.0 新增）

在 v13.2.0 中，`#[Queue]` 与 `#[Connection]` 开始接受 enum。你可以用 PHP enum 而非字符串字面量来类型安全地指定队列与连接。

```php theme={null}
// 队列名的 enum 定义
enum Queue: string
{
    case Default = 'default';
    case High = 'high';
    case Low = 'low';
    case Emails = 'emails';
    case Orders = 'orders';
}

// 连接的 enum 定义
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;

// 使用 enum 的类型安全指定
#[Queue(Queue::Orders)]
#[Connection(Connection::Redis)]
class ProcessOrder implements ShouldQueue
{
    // ...
}
```

<Tip>
  使用 enum 可以防止队列名或连接名的拼写错误，也能获得 IDE 补全。适合在应用中统一管理队列与连接名。
</Tip>

## 与传统类属性的对比

### 属性的优点

* **声明式** — 一眼就能看出 Job 的行为
* **类型安全** — 使用 enum 能获得 IDE 补全与类型检查
* **与继承兼容** — 子类可覆盖父类的属性
* **代码更精简** — 无需属性声明或方法覆写

### 属性的缺点

* **不能设置动态值** — 属性参数只能是编译期常量，无法使用变量或配置文件的值
* **需要熟悉** — 团队可能需要熟悉 PHP 8 的属性语法

### 需要动态值时

想在运行时决定值时，仍使用传统的方法覆写。

```php theme={null}
class ProcessOrder implements ShouldQueue
{
    // 动态 backoff 用方法定义
    public function backoff(): array
    {
        return [
            config('queue.backoff.first'),
            config('queue.backoff.second'),
        ];
    }
}
```

<Warning>
  属性会在 PHP 编译阶段解析，无法使用 `config()`、`env()` 等运行时值。需要动态配置时请继续使用类属性或方法。
</Warning>

## 实现机制

Laravel 内部使用 Reflection API 读取属性。当 Queue Worker 派发 Job 时，`ReadsQueueAttributes` trait（包含在 `InteractsWithQueue` 中）会通过反射发现属性并把值写入相应属性。

```php theme={null}
// 内部读取示意（简化）
$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 模型的属性同样通过反射在 `Model::booted()` 对应时机被读取。

## 下一步

<Columns cols={2}>
  <Card title="中级：队列与 Job" icon="layer-group" href="/zh/queues">
    学习 Laravel 队列系统的基本用法。
  </Card>

  <Card title="PHP Reflection API" icon="magnifying-glass" href="/zh/advanced/php-reflection">
    详解 Laravel 用于读取属性的 Reflection API 的机制。
  </Card>
</Columns>


## Related topics

- [PHP Reflection API](/zh/advanced/php-reflection.md)
- [Laravel 13 新功能汇总](/zh/blog/laravel-13-new-features.md)
- [2026 年 3 月 Laravel 更新](/zh/blog/changelog/202603.md)
- [Eloquent Observer 与模型事件](/zh/advanced/eloquent-observers.md)
- [邮件发送](/zh/mail.md)
