# 機能設計書 27-シリアライズ可能クロージャ

## 概要

本ドキュメントは、Laravel Frameworkにおけるシリアライズ可能クロージャ（SerializableClosure）連携機能の設計仕様を記載する。この機能は、PHPのクロージャをシリアライズ可能にし、キューやキャッシュでの利用を可能にする。

### 本機能の処理概要

シリアライズ可能クロージャは、通常はシリアライズできないPHPのクロージャ（無名関数）を、シリアライズ可能な形式に変換する機能である。Laravel\SerializableClosureパッケージを使用し、クロージャのシリアライズ・デシリアライズおよび署名検証を提供する。

**業務上の目的・背景**：Laravelのキューシステムやイベントリスナでは、ジョブやコールバックをシリアライズしてストレージ（Redis、Database等）に保存する必要がある。PHPの標準機能ではクロージャはシリアライズできないため、SerializableClosureを使用してクロージャを安全にシリアライズし、後でワーカーが復元して実行できるようにする。

**機能の利用シーン**：キュージョブでのクロージャ使用（dispatch(function() {...})）、キューでのバッチ処理、イベントリスナでのクロージャ、ルート定義でのクロージャ（キャッシュ時）など。

**主要な処理内容**：
1. クロージャをSerializableClosureでラップ
2. シリアライズ時にクロージャのコードと束縛変数を保存
3. 署名キー（APP_KEY）を使用した改ざん防止
4. デシリアライズ時にクロージャを復元
5. 元のクロージャを取得して実行

**関連システム・外部連携**：Laravel\SerializableClosureパッケージ、暗号化サービス（APP_KEYの共有）、キューシステム、イベントシステムとの連携。

**権限による制御**：本機能自体には権限制御はない。APP_KEYに基づく署名検証で安全性を担保。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | 内部機能 | キュー・イベント処理 |

## 機能種別

シリアライゼーション / キュー連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| closure | Closure | Yes | シリアライズ対象のクロージャ | 有効なクロージャ |
| secretKey | string | Yes | 署名用シークレットキー（APP_KEY） | 有効なキー |

### 入力データソース

- アプリケーションコードで定義されたクロージャ
- APP_KEY（環境変数または設定ファイル）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| serialized | string | シリアライズされたクロージャデータ |
| closure | Closure | 復元されたクロージャ |

### 出力先

- キューストレージ（Redis、Database等）
- キャッシュストレージ
- ワーカーでの実行

## 処理フロー

### 処理シーケンス

```
シリアライズ:
1. クロージャをSerializableClosureでラップ
   └─ new SerializableClosure($closure)

2. serialize()でシリアライズ
   └─ クロージャコードの抽出
   └─ 束縛変数のシリアライズ
   └─ 署名の生成（APP_KEY使用）

3. シリアライズされたデータをストレージに保存

デシリアライズ:
1. unserialize()でSerializableClosureを復元
   └─ 署名の検証
   └─ クロージャコードの復元
   └─ 束縛変数の復元

2. getClosure()で元のクロージャを取得

3. クロージャを実行
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{シリアライズ/デシリアライズ?}
    B -->|シリアライズ| C[new SerializableClosure]
    C --> D[クロージャコード抽出]
    D --> E[束縛変数シリアライズ]
    E --> F[署名生成]
    F --> G[serialize]
    G --> H[ストレージに保存]

    B -->|デシリアライズ| I[unserialize]
    I --> J[署名検証]
    J --> K{検証成功?}
    K -->|No| L[例外スロー]
    K -->|Yes| M[クロージャ復元]
    M --> N[getClosure]
    N --> O[クロージャ実行]

    H --> P[終了]
    O --> P
    L --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 署名検証 | デシリアライズ時にAPP_KEYで署名を検証 | 常時 |
| BR-02 | セキュリティキー設定 | EncryptionServiceProviderでSecretKeyを設定 | アプリケーション起動時 |
| BR-03 | 束縛変数 | クロージャの$this以外の束縛変数も一緒にシリアライズ | use句使用時 |

### 計算ロジック

- 署名計算: HMACベースの署名（詳細はSerializableClosureパッケージ実装）

## データベース操作仕様

本機能自体はデータベースを直接操作しない。キュードライバがdatabaseの場合、シリアライズされたデータがjobsテーブルに保存される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvalidSignatureException | 署名不正 | シリアライズ後にデータ改ざん | APP_KEYの確認、データ再生成 |
| ReflectionException | リフレクションエラー | クロージャの解析失敗 | クロージャコードの確認 |

### リトライ仕様

デシリアライズ失敗時のリトライはキューシステムの設定に依存。

## トランザクション仕様

本機能はトランザクションを使用しない。

## パフォーマンス要件

- クロージャのシリアライズはリフレクション処理を含むため、複雑なクロージャでは若干のオーバーヘッド
- 大量のクロージャを同時にシリアライズする場合はパフォーマンス考慮が必要

## セキュリティ考慮事項

- **署名検証**: APP_KEYを使用した署名で改ざんを検知
- **コード実行リスク**: 信頼できないソースからのシリアライズデータは実行しない
- **APP_KEY管理**: シークレットキーの漏洩は全クロージャの偽造を可能にする
- **unserialize脆弱性**: SerializableClosureは安全なunserializeを提供

## 備考

- EncryptionServiceProviderでSerializableClosure::setSecretKey()が呼び出される
- Laravel\SerializableClosureパッケージはComposerで別途インストール
- Queueableトレイトと連携してキュージョブで利用

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: セキュリティキー設定を理解する

まず、EncryptionServiceProviderでのSecretKey設定を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EncryptionServiceProvider.php | `src/Illuminate/Encryption/EncryptionServiceProvider.php` | registerSerializableClosureSecurityKey |

**主要処理フロー**:
- **45-54行目**: registerSerializableClosureSecurityKey()でSecretKeyを設定
- **49-50行目**: SerializableClosureクラスが存在し、APP_KEYが設定されている場合のみ実行
- **53行目**: SerializableClosure::setSecretKey()でAPP_KEYを設定

#### Step 2: キュージョブでの利用を理解する

CallQueuedClosureでのSerializableClosure使用を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CallQueuedClosure.php | `src/Illuminate/Queue/CallQueuedClosure.php` | クロージャのキュー実行 |

**主要処理フロー**:
- **51-54行目**: コンストラクタでSerializableClosureを受け取る
- **62-65行目**: create()でClosureからSerializableClosureを生成
- **73-76行目**: handle()でgetClosure()を使用してクロージャを実行
- **84-91行目**: onFailure()でコールバックをSerializableClosureでラップ

#### Step 3: イベントでの利用を理解する

QueuedClosureでのSerializableClosure使用を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | QueuedClosure.php | `src/Illuminate/Events/QueuedClosure.php` | イベントリスナでのクロージャ |
| 3-2 | InvokeQueuedClosure.php | `src/Illuminate/Events/InvokeQueuedClosure.php` | キューされたクロージャの呼び出し |

#### Step 4: ルートでの利用を理解する

ルートキャッシュ時のクロージャ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | RouteAction.php | `src/Illuminate/Routing/RouteAction.php` | ルートアクションのシリアライズ |

### プログラム呼び出し階層図

```
EncryptionServiceProvider::registerSerializableClosureSecurityKey()
    │
    └─ SerializableClosure::setSecretKey(APP_KEY)

dispatch(function() {...})
    │
    └─ CallQueuedClosure::create()
           │
           └─ new SerializableClosure($closure)
                  │
                  └─ serialize() ─── キューに保存
                         │
                         ▼
                  unserialize() ─── ワーカーで復元
                         │
                         └─ getClosure()
                                │
                                └─ クロージャ実行
```

### データフロー図

```
[ディスパッチ側]

Closure
    │
    ▼
new SerializableClosure()
    │
    ├─ クロージャコード抽出
    ├─ 束縛変数シリアライズ
    └─ 署名生成 (APP_KEY)
           │
           ▼
    serialize()
           │
           ▼
    キューストレージ
    (Redis/Database)


[ワーカー側]

キューストレージ
    │
    ▼
unserialize()
    │
    ├─ 署名検証 (APP_KEY)
    ├─ クロージャコード復元
    └─ 束縛変数復元
           │
           ▼
getClosure()
    │
    ▼
クロージャ実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EncryptionServiceProvider.php | `src/Illuminate/Encryption/EncryptionServiceProvider.php` | ソース | SecretKey設定 |
| CallQueuedClosure.php | `src/Illuminate/Queue/CallQueuedClosure.php` | ソース | キュークロージャジョブ |
| QueuedClosure.php | `src/Illuminate/Events/QueuedClosure.php` | ソース | イベントクロージャ |
| InvokeQueuedClosure.php | `src/Illuminate/Events/InvokeQueuedClosure.php` | ソース | クロージャ呼び出し |
| RouteAction.php | `src/Illuminate/Routing/RouteAction.php` | ソース | ルートアクション |
| Queueable.php | `src/Illuminate/Bus/Queueable.php` | ソース | Queueableトレイト |
| PendingBatch.php | `src/Illuminate/Bus/PendingBatch.php` | ソース | バッチ処理 |
