# 機能設計書 42-バウンドメソッド

## 概要

本ドキュメントは、Laravel FrameworkのBoundMethod機能の設計仕様を定義する。BoundMethodクラスは、メソッドやクロージャに対して依存性を自動注入しながら呼び出す機能を提供する。

### 本機能の処理概要

BoundMethodは、DIコンテナを利用して、任意のメソッドやクロージャの引数に依存関係を自動的に注入して呼び出す機能を提供する。コントローラのアクションメソッド、ジョブのハンドラ、イベントリスナーなど、様々な場所でメソッドインジェクションを実現する。

**業務上の目的・背景**：コンストラクタインジェクションだけでなく、個別のメソッド呼び出し時にも依存性注入を行いたいケースがある。例えば、コントローラのアクションメソッドで、そのメソッドでのみ必要なサービスを引数として受け取りたい場合に活用される。これにより、必要な依存関係を必要な場所でのみ取得でき、メモリ効率とコードの可読性が向上する。

**機能の利用シーン**：コントローラのアクションメソッド呼び出し、ジョブハンドラの実行、イベントリスナーの呼び出し、コンソールコマンドのハンドラ実行など、フレームワーク内部の様々な場所で利用される。

**主要な処理内容**：
1. callable または Class@method 形式の文字列を解析
2. リフレクションを使用してメソッドの引数情報を取得
3. 各引数について依存性をコンテナから解決
4. 解決した依存性を注入してメソッドを呼び出し
5. メソッドバインディングが登録されている場合はそちらを優先実行

**関連システム・外部連携**：DIコンテナ（Container）、ルーティング（コントローラディスパッチ）、キュー（ジョブ実行）、イベント（リスナー呼び出し）と連携する。

**権限による制御**：BoundMethod自体には権限制御は存在しないが、呼び出されるメソッド内で個別に権限チェックが行われることがある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングにバウンドメソッド関連の画面なし |

## 機能種別

メソッド呼び出し / 依存性注入

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| container | Container | Yes | DIコンテナインスタンス | - |
| callback | callable\|string | Yes | 呼び出し対象（クロージャ、配列、Class@method形式文字列） | - |
| parameters | array | No | メソッドに渡す追加パラメータ | - |
| defaultMethod | string\|null | No | デフォルトで呼び出すメソッド名 | - |

### 入力データソース

- ルーティング処理からのコントローラメソッド指定
- キューワーカーからのジョブハンドラ指定
- イベントディスパッチャからのリスナー指定
- 開発者コードからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | mixed | 呼び出されたメソッドの戻り値 |

### 出力先

- 呼び出し元へのメソッド戻り値

## 処理フロー

### 処理シーケンス

```
1. コールバック形式の判定
   └─ 文字列で@を含む場合はClass@method形式として処理
   └─ __invokeメソッドを持つクラスの場合はデフォルトメソッドを設定

2. Class@method形式の場合
   └─ callClassメソッドでクラスをインスタンス化し、メソッドを呼び出し

3. 通常のcallableの場合
   └─ callBoundMethodでメソッドバインディングを確認

4. メソッドバインディングがある場合
   └─ 登録されたコールバックを実行

5. メソッドバインディングがない場合
   └─ getMethodDependenciesで引数の依存性を解決
   └─ 解決した引数でメソッドを呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[call メソッド呼び出し] --> B{Class@method形式?}
    B -->|Yes| C[callClass]
    B -->|No| D{__invokeメソッド<br/>を持つクラス?}
    D -->|Yes| E[defaultMethod = __invoke]
    D -->|No| F[callBoundMethod]
    E --> F
    C --> G[コンテナでクラスをmake]
    G --> H[再帰的にcallを呼び出し]
    H --> F
    F --> I{メソッドバインディング<br/>登録済み?}
    I -->|Yes| J[callMethodBinding実行]
    I -->|No| K[getMethodDependencies]
    K --> L[リフレクションで<br/>引数情報取得]
    L --> M[各引数の依存性解決]
    M --> N[メソッド呼び出し]
    J --> O[結果返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-42-1 | メソッドバインディング優先 | コンテナにメソッドバインディングが登録されている場合、そちらを優先実行 | hasMethodBinding が true |
| BR-42-2 | 名前付きパラメータ優先 | parametersに同名のキーがある場合、コンテナ解決よりも優先 | parameters配列にキーが存在 |
| BR-42-3 | 型ヒントによる解決 | 引数に型ヒントがある場合、その型をコンテナから解決 | getParameterClassName が非null |
| BR-42-4 | デフォルト値使用 | 型ヒントがなく、デフォルト値がある場合はそれを使用 | isDefaultValueAvailable が true |

### 計算ロジック

該当なし

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | BoundMethod自体はデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvalidArgumentException | 引数エラー | Class@method形式でメソッドが指定されていない | メソッド名を指定するか、defaultMethodを設定 |
| BindingResolutionException | 依存解決失敗 | 型ヒントのクラスが解決できない | バインディングを登録するか、具象クラスを指定 |
| ReflectionException | リフレクションエラー | 指定されたクラスやメソッドが存在しない | クラス名・メソッド名を確認 |

### リトライ仕様

リトライ処理は実装されていない。

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

BoundMethodはトランザクション管理を行わない。

## パフォーマンス要件

- リフレクションのコストが発生するが、メソッド呼び出しごとに1回のみ
- 依存性解決はコンテナのキャッシュ機構を利用

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

- 外部入力からClass@method形式の文字列を直接渡さないこと
- 呼び出し対象メソッドのアクセス制御を確認

## 備考

- Container::call() メソッドから呼び出される
- 静的メソッドのみで構成されるユーティリティクラス

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

BoundMethodは状態を持たない静的クラスのため、入出力パラメータを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | callメソッドのシグネチャ（14-38行目）で入力を把握 |

**読解のコツ**: BoundMethodはすべて静的メソッドで構成されており、状態を持たない。callメソッドを起点として、他のメソッドがどのように呼び出されるかを追う。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | call() メソッド（25-38行目）がエントリーポイント |
| 2-2 | Container.php | `src/Illuminate/Container/Container.php` | Container::call() （785-806行目）がBoundMethod::callを呼び出す |

**主要処理フロー**:
1. **27-29行目**: __invokeメソッドを持つクラスの場合、defaultMethodに__invokeを設定
2. **31-33行目**: @を含む文字列またはdefaultMethodがある場合、callClassを呼び出し
3. **35-37行目**: それ以外はcallBoundMethodでメソッドバインディング確認後に実行

#### Step 3: Class@method形式の処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | callClass()（51-71行目）の処理フロー |

**主要処理フロー**:
- **53行目**: @で文字列を分割
- **58-60行目**: メソッド名を決定（2番目の要素またはdefaultMethod）
- **62-64行目**: メソッドが指定されていない場合は例外
- **66-70行目**: コンテナでクラスをmakeし、再帰的にcallを呼び出し

#### Step 4: 依存性解決処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | getMethodDependencies()（122-131行目） |
| 4-2 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | addDependencyForCallParameter()（165-206行目） |
| 4-3 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | getCallReflector()（141-152行目） |

**主要処理フロー**:
- **126-128行目**: 各パラメータについてaddDependencyForCallParameterを呼び出し
- **130行目**: 解決した依存性とparametersをマージ
- **173-176行目**: パラメータ名でparametersに値がある場合はそれを使用
- **177-178行目**: コンテキスト属性がある場合はコンテナから解決
- **179-192行目**: 型ヒントがある場合はコンテナでmake
- **193-194行目**: デフォルト値がある場合はそれを使用

#### Step 5: メソッドバインディングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | callBoundMethod()（81-97行目） |
| 5-2 | BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | normalizeMethod()（105-110行目） |
| 5-3 | Container.php | `src/Illuminate/Container/Container.php` | hasMethodBinding()（422-425行目）、bindMethod()（434-437行目） |

**主要処理フロー**:
- **83-85行目**: 配列形式のcallableでない場合は即座にデフォルトを実行
- **90行目**: normalizeMethodでClass@method形式に正規化
- **92-94行目**: メソッドバインディングがあれば実行

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

```
Container::call($callback, $parameters, $defaultMethod)
    │
    └─ BoundMethod::call($container, $callback, $parameters, $defaultMethod)
           │
           ├─ isCallableWithAtSign($callback)
           │      └─ str_contains($callback, '@')
           │
           ├─ [Class@method形式の場合]
           │  callClass($container, $target, $parameters, $defaultMethod)
           │      │
           │      ├─ explode('@', $target)
           │      │
           │      ├─ $container->make($class)
           │      │
           │      └─ call($container, [$instance, $method], $parameters) [再帰]
           │
           └─ [通常のcallableの場合]
              callBoundMethod($container, $callback, $default)
                  │
                  ├─ normalizeMethod($callback)
                  │
                  ├─ $container->hasMethodBinding($method)
                  │
                  ├─ [バインディングあり]
                  │  $container->callMethodBinding($method, $callback[0])
                  │
                  └─ [バインディングなし]
                     getMethodDependencies($container, $callback, $parameters)
                         │
                         ├─ getCallReflector($callback)
                         │      └─ new ReflectionMethod / ReflectionFunction
                         │
                         └─ addDependencyForCallParameter($container, $parameter, ...)
                                │
                                ├─ Util::getContextualAttributeFromDependency()
                                │
                                ├─ Util::getParameterClassName()
                                │
                                └─ $container->make($className)
```

### データフロー図

```
[入力]                        [処理]                           [出力]

$callback            ───▶  isCallableWithAtSign()   ───▶  形式判定結果
(callable|string)          (形式判定)

"Class@method"       ───▶  callClass()              ───▶  [$instance, $method]
(文字列)                   (@で分割、クラスmake)

$callback            ───▶  getCallReflector()       ───▶  ReflectionMethod/Function
(callable)                 (リフレクション取得)

ReflectionParameter  ───▶  addDependencyForCallParameter() ───▶ 解決済み依存性
(パラメータ情報)            (依存性解決)

[$callback, $deps]   ───▶  $callback(...$deps)      ───▶  メソッド戻り値
(呼び出し準備完了)          (メソッド実行)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BoundMethod.php | `src/Illuminate/Container/BoundMethod.php` | ソース | メソッドインジェクションのメイン実装 |
| Container.php | `src/Illuminate/Container/Container.php` | ソース | call()メソッドがBoundMethodを使用 |
| Util.php | `src/Illuminate/Container/Util.php` | ソース | getParameterClassName、getContextualAttributeFromDependency |
| ControllerDispatcher.php | `src/Illuminate/Routing/ControllerDispatcher.php` | ソース | コントローラメソッド呼び出しでBoundMethodを使用 |
