> ## 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 Attributes

> 說明如何使用 Laravel 13 導入與強化的 PHP Attributes，以更宣告式的方式撰寫 Job 或 Model 的設定。

## 什麼是 PHP Attributes

PHP Attributes 是 PHP 8.0 導入的原生 metadata 語法。可對類別、方法、屬性、函式等以 `#[AttributeName]` 形式加註元資訊。

Laravel 於框架本體積極採用 PHP Attributes，可以宣告式撰寫 Job 或 Eloquent 模型的設定。於 Laravel 13（v13.2.0）中，Queue attribute 可接受 enum。相較於傳統的類別屬性或方法覆寫，使用 attribute 可寫出更易讀且簡潔的程式碼。

```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];
}

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

<Tip>
  Attributes 於 PHP 8.0 以後可使用。Laravel 13 要求 PHP 8.3 以上，因此所有環境皆可使用 attribute。
</Tip>

## Queue 相關 Attributes

Queue Job 相關的 attributes 皆位於 `Illuminate\Queue\Attributes` 命名空間。

### `#[Queue]` — 指定 Queue 名稱

指定 Job 送往的預設 Queue 名稱。

```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]` attribute 的 target 被設為 `Attribute::TARGET_CLASS`，因此只能套用於類別。
</Info>

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

指定 Job 使用的預設 Queue Connection。

```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]` — 指定重試 backoff 時間

指定 Job 失敗時，重試前的等待時間（秒）。傳入多個值時，每次重試可設定不同的等待時間（可變長引數支援）。

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

// 固定的等待時間（所有重試共通等待 60 秒）
#[Backoff(60)]
class SendEmail implements ShouldQueue
{
    // ...
}

// 各次重試不同的等待時間（指數 backoff）
#[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]` — 指定 Timeout

指定 Job 的最大執行時間（秒）。超過此時間時，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 重複執行的 lock 期間（秒）。搭配 `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 序列化時不將模型的關聯納入。可精簡送往 Queue 的資料量。

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

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

### `#[FailOnTimeout]` — Timeout 時視為失敗

當發生 Timeout 時，將 Job 記錄為失敗（預設 Timeout 不會被記錄為失敗）。

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

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

## 組合多個 Queue Attributes

可以組合這些 attribute，宣告式設定 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 相關 Attributes

Eloquent 模型的 attributes 位於 `Illuminate\Database\Eloquent\Attributes` 命名空間。Laravel 13 新增了大量 attribute。

### `#[ScopedBy]` — 指定 Global Scope

以 attribute 指定要自動套用至模型的 Global Scope 類別。支援繼承，並具有 `IS_REPEATABLE` 旗標，可指定多個 Scope。

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

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
    // 不再需要於 booted() 註冊 Scope
}
```

要套用多個 Scope，重複標註 attribute 或以陣列傳入。

```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

以 attribute 指定關聯至模型的 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

以 attribute 指定模型所使用的自訂 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

以 attribute 指定模型的 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]` — 一次指定 Table 相關設定

可以一個 attribute 一次指定表格名稱、主鍵、時間戳記等多個 Table 相關設定。

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

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

`Table` attribute 可設定的選項如下。

| 參數             | 對應屬性            | 說明                           |
| -------------- | --------------- | ---------------------------- |
| `name`         | `$table`        | 表格名稱                         |
| `key`          | `$primaryKey`   | 主鍵欄位名稱                       |
| `keyType`      | `$keyType`      | 主鍵的型別（`'int'`, `'string'` 等） |
| `incrementing` | `$incrementing` | 主鍵的自動遞增                      |
| `timestamps`   | `$timestamps`   | 時間戳記啟用/停用                    |
| `dateFormat`   | `$dateFormat`   | 日期格式                         |

### `#[Scope]` — 將方法定義為本地 Scope

可將不含 `scope` 前綴的方法定義為 Eloquent 的本地 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}
// 傳統上方法名稱需加上「scope」前綴
// public function scopeActive(Builder $query): void

// 使用 attribute 後，方法名稱直接就是 Scope 名稱
User::query()->active()->verified()->get();
```

### `#[UseFactory]` — 指定 Factory 類別

以 attribute 指定模型所使用的自訂 Factory 類別。

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

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

### 其他 Eloquent Attributes

| Attribute                                                  | 說明                           |
| ---------------------------------------------------------- | ---------------------------- |
| `#[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 取代字串字面值，型別安全地指定 Queue 與 Connection。

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

// Connection 的 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 可防止 Queue 名稱或 Connection 名稱的拼字錯誤，並可利用 IDE 的補完。適合在整個應用程式集中管理 Queue 名稱與 Connection 名稱。
</Tip>

## 與傳統類別屬性的比較

### Attribute 的優點

* **宣告式** — 觀察類別開頭即可一眼看出 Job 的行為
* **型別安全** — 使用 enum 可享有 IDE 補完與型別檢查
* **與繼承的親和性** — 父類別的 attribute 可於子類別覆寫
* **減少程式碼** — 不需宣告屬性或覆寫方法

### Attribute 的缺點

* **無法設定動態值** — attribute 的引數僅能為編譯時常數。無法使用變數或設定檔的值
* **需適應** — 團隊有時需要適應 PHP 8 的 attribute 語法

### 需要動態值時

若希望於執行時決定值，仍使用傳統的方法覆寫。

```php theme={null}
class ProcessOrder implements ShouldQueue
{
    // 動態的 backoff 以方法定義
    public function backoff(): array
    {
        return [
            config('queue.backoff.first'),
            config('queue.backoff.second'),
        ];
    }
}
```

<Warning>
  Attributes 於 PHP 編譯時被解析。無法使用 `config()` 或 `env()` 這類執行時的值。若需要動態設定，請繼續使用類別屬性或方法。
</Warning>

## 實作機制

Laravel 內部使用 Reflection API 讀取 attribute。當 Queue Worker dispatch Job 時，`ReadsQueueAttributes` trait（包含於 `InteractsWithQueue` 中）以 reflection 偵測 attribute，並將值設定至對應屬性。

```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 模型的 attribute 也同樣，於相當於 `Model::booted()` 的時機以 reflection 讀取。

## 下一步

<Columns cols={2}>
  <Card title="中階：Queue 與 Job" icon="layer-group" href="/zh-TW/queues">
    學習 Laravel Queue 系統的基本用法。
  </Card>

  <Card title="PHP Reflection API" icon="magnifying-glass" href="/zh-TW/advanced/php-reflection">
    詳細說明 Laravel 讀取 attribute 所使用的 Reflection API 機制。
  </Card>
</Columns>


## Related topics

- [Controller 的 PHP Attributes](/zh-TW/advanced/controller-attributes.md)
- [PHP Reflection API](/zh-TW/advanced/php-reflection.md)
- [Eloquent Bootable Traits](/zh-TW/advanced/eloquent-bootable-traits.md)
- [Laravel AI SDK](/zh-TW/ai-sdk.md)
- [Eloquent Observer 與模型事件](/zh-TW/advanced/eloquent-observers.md)
