# 機能設計書：リフレクションヘルパー

## 1. 機能概要

### 1.1 機能名
リフレクションヘルパー（Reflection Helpers）

### 1.2 機能説明
PHP のリフレクション API を活用するためのヘルパー機能群。クラス属性の取得、パラメータ型の解析、クロージャの型ヒント取得、遅延インスタンス化（Lazy Objects）などを提供し、フレームワーク内部や依存性注入で活用される。

### 1.3 関連画面
- なし（フレームワーク内部機能）

## 2. 機能詳細

### 2.1 処理フロー

```
[対象クラス/クロージャ]
    |
    v
[Reflector / ReflectsClosures]
    |
    +-- getParameterClassName() -> 型名取得
    +-- getClassAttribute() -> 属性取得
    +-- closureParameterTypes() -> クロージャ引数型取得
    +-- closureReturnTypes() -> クロージャ戻り値型取得
    |
    v
[型情報 / 属性インスタンス]
```

### 2.2 クラス構成

| クラス名 | 役割 |
|---------|------|
| Reflector | リフレクションユーティリティ |
| ReflectsClosures | クロージャリフレクショントレイト |
| helpers.php | lazy(), proxy() ヘルパー関数 |

### 2.3 主要メソッド

#### Reflector クラス

| メソッド | 説明 | 引数 | 戻り値 |
|---------|------|------|--------|
| `isCallable()` | コーラブル判定 | `$var, $syntaxOnly` | `bool` |
| `getClassAttribute()` | クラス属性取得 | `$objectOrClass, $attribute, $ascend` | `object\|null` |
| `getClassAttributes()` | クラス属性一覧取得 | `$objectOrClass, $attribute, $includeParents` | `Collection` |
| `getParameterClassName()` | パラメータの型名取得 | `$parameter` | `string\|null` |
| `getParameterClassNames()` | パラメータの型名一覧取得 | `$parameter` | `array` |
| `isParameterSubclassOf()` | パラメータ型がサブクラスか判定 | `$parameter, $className` | `bool` |
| `isParameterBackedEnumWithStringBackingType()` | 文字列BackedEnum判定 | `$parameter` | `bool` |

#### ReflectsClosures トレイト

| メソッド | 説明 | 引数 | 戻り値 |
|---------|------|------|--------|
| `firstClosureParameterType()` | 最初のパラメータ型取得 | `$closure` | `string` |
| `firstClosureParameterTypes()` | 最初のパラメータ型一覧 | `$closure` | `array` |
| `closureParameterTypes()` | 全パラメータ型取得 | `$closure` | `array` |
| `closureReturnTypes()` | 戻り値型取得 | `$closure` | `array` |

#### ヘルパー関数

| 関数名 | 説明 | 引数 | 戻り値 |
|--------|------|------|--------|
| `lazy()` | 遅延ゴーストインスタンス作成 | `$class, $callback, $options, $eager` | `object` |
| `proxy()` | 遅延プロキシインスタンス作成 | `$class, $callback, $options, $eager` | `object` |

### 2.4 ビジネスルール

1. **型解析**
   - ReflectionNamedType からクラス名を抽出
   - Union Type にも対応（複数型）
   - `self`, `parent` は適切に解決

2. **属性取得**
   - PHP 8 Attributes をリフレクションで取得
   - 親クラスの属性も再帰的に取得可能

3. **遅延インスタンス化**
   - PHP 8.4 の Lazy Objects 機能を活用
   - ゴースト（Ghost）: 初期化を遅延
   - プロキシ（Proxy）: 別インスタンスに委譲

4. **クロージャ解析**
   - クロージャの引数型を取得
   - 戻り値型も取得可能
   - 依存性注入の自動解決に活用

## 3. 入出力仕様

### 3.1 入力

| 項目 | 型 | 説明 |
|-----|-----|------|
| parameter | `ReflectionParameter` | 解析対象パラメータ |
| closure | `Closure` | 解析対象クロージャ |
| objectOrClass | `object\|string` | 属性取得対象 |

### 3.2 出力

| 項目 | 型 | 説明 |
|-----|-----|------|
| className | `string\|null` | 型名 |
| classNames | `array` | 型名配列（Union Type対応） |
| attribute | `object\|null` | 属性インスタンス |

## 4. 依存関係

### 4.1 内部依存

| パッケージ | 用途 |
|-----------|------|
| Illuminate\Support\Collection | 属性コレクション |
| Illuminate\Support\Reflector | リフレクションユーティリティ |

### 4.2 外部依存

| パッケージ | 用途 |
|-----------|------|
| PHP Reflection API | 標準リフレクション |

## 5. エラー処理

| エラー種別 | 発生条件 | 処理内容 |
|-----------|---------|---------|
| RuntimeException | クロージャにパラメータがない | 例外スロー |
| RuntimeException | 型ヒントがない | 例外スロー |
| ReflectionException | リフレクション失敗 | 例外スロー |

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

### 6.1 推奨読解順序

1. **Reflector クラス** (`Support/Reflector.php`)
   - **12-14行目**: クラス定義
   - **21-58行目**: `isCallable()` - コーラブル判定
     - **23-25行目**: 配列でない場合は標準判定
     - **37-38行目**: クラス存在確認
     - **45-47行目**: メソッド存在確認
     - **49-51行目**: __call マジックメソッド対応
     - **53-55行目**: __callStatic マジックメソッド対応
   - **70-73行目**: `getClassAttribute()` - 単一属性取得
   - **86-100行目**: `getClassAttributes()` - 属性一覧取得
     - **92-97行目**: 親クラスを再帰的に走査
   - **108-117行目**: `getParameterClassName()` - パラメータ型名取得
   - **125-144行目**: `getParameterClassNames()` - Union Type対応
   - **153-168行目**: `getTypeName()` - 型名解決（self/parent対応）
   - **177-184行目**: `isParameterSubclassOf()` - サブクラス判定
   - **192-212行目**: `isParameterBackedEnumWithStringBackingType()` - BackedEnum判定

2. **ReflectsClosures トレイト** (`Support/Traits/ReflectsClosures.php`)
   - **24-37行目**: `firstClosureParameterType()` - 最初の引数型
   - **48-73行目**: `firstClosureParameterTypes()` - 最初の引数型一覧
   - **83-96行目**: `closureParameterTypes()` - 全引数型
   - **106-125行目**: `closureReturnTypes()` - 戻り値型

3. **ヘルパー関数** (`Reflection/helpers.php`)
   - **17-50行目**: `lazy()` - 遅延ゴースト作成
     - **35-38行目**: newLazyGhost() でゴースト作成
     - **45-47行目**: eager プロパティの先行設定
   - **65-96行目**: `proxy()` - 遅延プロキシ作成
     - **85-89行目**: newLazyProxy() でプロキシ作成

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

```
Reflector::getParameterClassName($parameter)
├── $parameter->getType()
├── ReflectionNamedType かつ !isBuiltin()
└── Reflector::getTypeName($parameter, $type)
    ├── $type->getName()
    └── 'self' / 'parent' 解決

Reflector::getClassAttributes($class, $attribute, true)
└── do-while ループ
    ├── ReflectionClass::getAttributes($attribute)
    ├── ReflectionAttribute::newInstance()
    └── ReflectionClass::getParentClass()

lazy(MyClass::class, fn ($instance) => $instance->__construct(...))
└── ReflectionClass::newLazyGhost()
    └── コールバック実行時に初期化
```

### 6.3 データフロー図

```
[対象クラス/パラメータ/クロージャ]
    |
    v
[PHP Reflection API]
    |
    +-- ReflectionClass
    +-- ReflectionMethod
    +-- ReflectionParameter
    +-- ReflectionFunction
    +-- ReflectionAttribute
    |
    v
[Reflector / ReflectsClosures]
    |
    +-- 型名抽出
    +-- 属性取得
    +-- Union Type 解決
    +-- self/parent 解決
    |
    v
[型情報 / 属性インスタンス]
```

### 6.4 読解のコツ

- **PHP 8 Attributes**: `#[Attribute]` 構文で定義された属性をリフレクションで取得
- **Union Type**: `int|string` のような型は `ReflectionUnionType` として取得
- **PHP 8.4 Lazy Objects**: `newLazyGhost()`, `newLazyProxy()` は PHP 8.4 新機能
- **self/parent 解決**: 型名が `self`/`parent` の場合、宣言クラスに解決

### 6.5 関連ファイル一覧

| ファイルパス | 種別 | 役割 |
|------------|------|------|
| `src/Illuminate/Support/Reflector.php` | Class | リフレクションユーティリティ |
| `src/Illuminate/Support/Traits/ReflectsClosures.php` | Trait | クロージャリフレクション |
| `src/Illuminate/Reflection/helpers.php` | Helper | lazy(), proxy() 関数 |

## 7. 使用例

```php
use Illuminate\Support\Reflector;
use Illuminate\Support\Traits\ReflectsClosures;

// パラメータ型名取得
$method = new ReflectionMethod(UserController::class, 'store');
$parameters = $method->getParameters();

foreach ($parameters as $parameter) {
    $className = Reflector::getParameterClassName($parameter);
    // Request クラスなどの型名が取得できる
}

// Union Type 対応
$classNames = Reflector::getParameterClassNames($parameter);
// ['App\Models\User', 'App\Models\Admin'] など

// サブクラス判定
if (Reflector::isParameterSubclassOf($parameter, Model::class)) {
    // Eloquent モデルの場合
}

// クラス属性取得
#[Middleware('auth')]
class AdminController {}

$attribute = Reflector::getClassAttribute(
    AdminController::class,
    Middleware::class
);
// Middleware インスタンス

// 親クラスの属性も取得
$attributes = Reflector::getClassAttributes(
    ChildController::class,
    Middleware::class,
    includeParents: true
);
// 親クラスの属性も含む Collection

// クロージャの型解析
class EventSubscriber {
    use ReflectsClosures;

    public function subscribe($events) {
        $events->listen(function (UserCreated $event) {
            // ...
        });
    }

    public function getEventType(Closure $handler) {
        return $this->firstClosureParameterType($handler);
        // 'App\Events\UserCreated'
    }
}

// 遅延インスタンス化（PHP 8.4）
$user = lazy(User::class, function ($user) {
    return ['name' => 'John', 'email' => 'john@example.com'];
});
// プロパティアクセス時に初期化される

// 遅延プロキシ
$service = proxy(HeavyService::class, function () {
    return new HeavyService(/* expensive setup */);
});
// メソッド呼び出し時に実インスタンスに委譲
```

## 8. 改版履歴

| バージョン | 日付 | 変更内容 |
|-----------|------|---------|
| 1.0.0 | - | 初版作成 |
