# 機能設計書 10-DependencyInjection

## 概要

本ドキュメントは、Symfony DependencyInjectionコンポーネントの機能設計を記述する。DependencyInjectionはアプリケーション内のオブジェクト構築方法を標準化・集約するDIコンテナを提供し、サービスコンテナ、コンパイラパス、オートワイヤリングに対応する。

### 本機能の処理概要

DependencyInjectionコンポーネントは、依存性注入（Dependency Injection）パターンを実装するサービスコンテナを提供する。サービス（オブジェクト）の定義、構築、取得を一元管理し、アプリケーション全体の依存関係をコンテナに集約する。コンパイルフェーズでサービスグラフを最適化し、PHPコードとしてダンプすることで高速なサービス解決を実現する。

**業務上の目的・背景**：大規模アプリケーションでは、オブジェクト間の依存関係が複雑化する。DIコンテナはオブジェクトの構築方法を宣言的に定義し、依存関係の自動解決（オートワイヤリング）により、保守性とテスタビリティを向上させる。Symfonyフレームワークの核心技術である。

**機能の利用シーン**：アプリケーション全体のサービス管理、コントローラーへの依存注入、イベントリスナーの登録、設定値の管理等、Symfonyアプリケーションのあらゆる場面で利用される。開発時はContainerBuilderでサービスを定義・コンパイルし、本番時はコンパイル済みコンテナでサービスを取得する。

**主要な処理内容**：
1. サービス定義の管理（Definition、ChildDefinition、Alias）
2. コンテナのコンパイル（コンパイラパスの実行）
3. オートワイヤリング（型ヒントによる依存自動解決）
4. サービスローダー（YAML、XML、PHP、クロージャ、ディレクトリ）
5. パラメータバッグ（設定値管理、環境変数プレースホルダー）
6. 環境変数プロセッサー（EnvVarProcessor）
7. レイジープロキシ生成
8. サービスロケーター（ServiceLocator）
9. タグ付きサービス管理
10. PHPコードへのダンプ（PhpDumper）
11. 式言語統合（ExpressionLanguage）
12. PHP 8属性によるサービス設定（#[Autowire]、#[AutoconfigureTag]等）

**関連システム・外部連携**：Config（設定ファイルの読み込み）、ExpressionLanguage（式評価）、HttpKernel（Kernel基底クラスによるコンテナビルド）、FrameworkBundle（サービス定義の提供）

**権限による制御**：DIコンテナ自体には権限制御はない。コンテナ経由で取得したサービス（Security等）が権限制御を行う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|

DependencyInjectionコンポーネントは画面機能マッピングに直接関連する画面がない（基盤コンポーネントのため）。

## 機能種別

フレームワーク基盤 / DIコンテナ / サービス管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| services設定 | array/YAML/XML/PHP | No | サービス定義 | コンパイラパスによる検証 |
| parameters | array | No | パラメータ定義 | ParameterBagによる型検証 |
| extensions | array | No | バンドル拡張の設定値 | Configuration Treeによるバリデーション |

### 入力データソース

- services.yaml/xml/php設定ファイル
- バンドル拡張（Extension）からのサービス定義
- PHP属性（#[AsController]、#[AsEventListener]等）
- 環境変数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| container | Container | コンパイル済みDIコンテナ |
| services | object[] | インスタンス化されたサービスオブジェクト群 |
| parameters | array | 解決済みパラメータ値 |

### 出力先

- コンパイル済みPHPクラス（var/cache/ContainerXXXXXX/Container.php）
- ランタイムでのサービスインスタンス返却

## 処理フロー

### 処理シーケンス

```
1. ContainerBuilder生成
   └─ ParameterBag初期化
2. サービス定義の読み込み
   └─ Loader（YAML/XML/PHP/Closure）でサービス定義を登録
3. 拡張設定の読み込み
   └─ バンドル拡張（Extension::load()）でサービス定義を追加
4. コンパイラパスの実行
   └─ BEFORE_OPTIMIZATION -> OPTIMIZATION -> BEFORE_REMOVING -> REMOVING -> AFTER_REMOVING
5. コンテナのコンパイル
   └─ パラメータ解決、エイリアス解決、サービスグラフ最適化
6. PHPダンプ
   └─ PhpDumperによるPHPクラスコード生成
7. ランタイムサービス取得
   └─ Container::get()でサービスインスタンスを取得（必要時にインスタンス化）
```

### フローチャート

```mermaid
flowchart TD
    A[ContainerBuilder生成] --> B[Loader: サービス定義読み込み]
    B --> C[Extension::load: バンドル設定]
    C --> D[BEFORE_OPTIMIZATION パス]
    D --> E[OPTIMIZATION パス]
    E --> F[BEFORE_REMOVING パス]
    F --> G[REMOVING パス]
    G --> H[AFTER_REMOVING パス]
    H --> I[コンテナコンパイル]
    I --> J[PhpDumper: PHPコード生成]
    J --> K[キャッシュ保存]

    L[Container::get] --> M{インスタンス済み?}
    M -->|Yes| N[キャッシュから返却]
    M -->|No| O[ファクトリメソッド実行]
    O --> P[依存サービス解決]
    P --> Q[インスタンス生成]
    Q --> R[キャッシュに保存]
    R --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | シングルトン | デフォルトでサービスはshared=trueであり、同一インスタンスが再利用される | shared設定未変更時 |
| BR-02 | 遅延インスタンス化 | サービスはget()呼び出し時に初めてインスタンス化される | 常時 |
| BR-03 | 循環参照検出 | サービス間の循環依存はコンパイル時に検出される | コンパイル時 |
| BR-04 | 無効参照の動作 | EXCEPTION_ON_INVALID_REFERENCE（デフォルト）、NULL_ON_INVALID_REFERENCE等5段階の動作を選択可能 | サービス参照時 |
| BR-05 | オートワイヤリング | 型ヒントに基づいてコンストラクタ引数を自動解決する | autowire=true時 |
| BR-06 | オートコンフィギュレーション | インターフェース実装に基づいてタグを自動付与する | autoconfigure=true時 |
| BR-07 | コンパイラパス優先度 | BEFORE_OPTIMIZATION(-1000) -> OPTIMIZATION(0) -> BEFORE_REMOVING(-100) -> REMOVING(0) -> AFTER_REMOVING(0) | コンパイル時 |

### 計算ロジック

- 環境変数プロセッサー：`%env(TYPE:NAME)%`形式のプレースホルダーを実行時に環境変数から解決し、TYPE（string, bool, int, float, json, base64, file等）に応じて変換する。

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

DependencyInjectionコンポーネント自体はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ServiceNotFoundException | 存在しないサービスIDでget()を呼び出し | サービス定義の確認 |
| - | ServiceCircularReferenceException | サービス間の循環依存 | 依存関係の見直し |
| - | ParameterNotFoundException | 存在しないパラメータの参照 | パラメータ定義の確認 |
| - | ParameterCircularReferenceException | パラメータ間の循環参照 | パラメータ定義の見直し |
| - | InvalidArgumentException | 不正なサービス定義 | サービス定義の修正 |
| - | RuntimeException | ランタイムエラー | サービス実装の確認 |
| - | EnvNotFoundException | 環境変数が未定義 | 環境変数の設定 |
| - | BadMethodCallException | コンパイル後の不正操作 | コンパイル前に操作を実行 |
| - | LogicException | ロジックエラー（例：コンパイル後のDefinition追加） | 処理順序の確認 |

### リトライ仕様

リトライ機能なし。

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

トランザクション管理なし。

## パフォーマンス要件

- コンパイル済みコンテナはPHPクラスとしてダンプされ、opcacheで高速にロードされる
- サービスインスタンスはshared=trueの場合、初回取得後にキャッシュされる
- レイジープロキシにより、未使用サービスのインスタンス化を遅延できる
- ServiceLocatorにより、必要なサービスのみを遅延取得できる

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

- コンパイル済みコンテナPHPファイルにはサービス構築ロジックが含まれるため、適切なファイルパーミッションが必要
- 環境変数プロセッサーを通じて機密情報を安全に管理
- パブリックサービスの制限（デフォルトでprivate）により、不要なサービス公開を防止

## 備考

- PHP 8属性（#[Autowire]、#[AutoconfigureTag]、#[When]等）によるサービス設定をサポート
- LazyClosure、RewindableGenerator等の高度な引数型をサポート
- ReverseContainerにより、サービスインスタンスからサービスIDへの逆引きが可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Definition.php | `src/Symfony/Component/DependencyInjection/Definition.php` | サービス定義のデータ構造。クラス名、引数、メソッドコール、タグ等 |
| 1-2 | ChildDefinition.php | `src/Symfony/Component/DependencyInjection/ChildDefinition.php` | 親定義を継承するサービス定義 |
| 1-3 | Alias.php | `src/Symfony/Component/DependencyInjection/Alias.php` | サービスエイリアス定義 |
| 1-4 | Reference.php | `src/Symfony/Component/DependencyInjection/Reference.php` | サービス参照（他サービスへの依存を表現） |
| 1-5 | Parameter.php | `src/Symfony/Component/DependencyInjection/Parameter.php` | パラメータ参照 |

**読解のコツ**: Definitionクラスがサービス1つの全情報を保持する。setClass(), setArguments(), addMethodCall(), addTag()等のビルダーパターンでサービスの構成を宣言的に記述する。

#### Step 2: コンテナ基底クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Container.php | `src/Symfony/Component/DependencyInjection/Container.php` | ランタイムコンテナ。get(), has(), getParameter()等 |

**主要処理フロー**:
1. **51-52行目**: Containerクラス定義（ContainerInterface, ResetInterface実装）
2. **53-62行目**: プロパティ定義（services, privates, fileMap, methodMap, factories, aliases等）
3. **70-73行目**: コンストラクタ。EnvPlaceholderParameterBagをデフォルトで使用
4. **78-80行目**: compile()メソッド - パラメータ解決とフリーズ

#### Step 3: ContainerBuilderを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ContainerBuilder.php | `src/Symfony/Component/DependencyInjection/ContainerBuilder.php` | ビルド時コンテナ。サービス定義の登録・コンパイル |

**主要処理フロー**:
- **59行目**: ContainerはContainerを継承しTaggedContainerInterfaceを実装
- **64-99行目**: プロパティ定義（extensions, definitions, aliasDefinitions, resources, extensionConfigs, compiler等）

#### Step 4: コンパイラを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Compiler/Compiler.php | `src/Symfony/Component/DependencyInjection/Compiler/Compiler.php` | コンパイラメインクラス |
| 4-2 | Compiler/PassConfig.php | `src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php` | コンパイラパスの優先度管理 |

#### Step 5: ローダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Loader/YamlFileLoader.php | `src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php` | YAMLサービス定義のローダー |
| 5-2 | Loader/PhpFileLoader.php | `src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php` | PHPサービス定義のローダー |

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

```
ContainerBuilder::compile()
    |
    +-- MergeExtensionConfigurationPass::process()
    |       +-- Extension::load(configs, ContainerBuilder)
    |
    +-- Compiler::compile(ContainerBuilder)
            |
            +-- [BEFORE_OPTIMIZATION パス群]
            |       +-- ResolveDefinitionTemplatesPass
            |       +-- ...
            |
            +-- [OPTIMIZATION パス群]
            |       +-- AutowirePass
            |       +-- ResolveReferencesToAliasesPass
            |       +-- ...
            |
            +-- [BEFORE_REMOVING パス群]
            |       +-- CheckCircularReferencesPass
            |       +-- ...
            |
            +-- [REMOVING パス群]
            |       +-- RemoveUnusedDefinitionsPass
            |       +-- ...
            |
            +-- [AFTER_REMOVING パス群]

Container::get(id)
    |
    +-- [services配列に存在] return services[id]
    |
    +-- [methodMapに存在] return this->methodName()
    |
    +-- [fileMapに存在] require file; return this->methodName()
    |
    +-- [aliasesに存在] return get(aliases[id])
    |
    +-- ServiceNotFoundException
```

### データフロー図

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

services.yaml          --->  YamlFileLoader::load()        --->  Definition群
services.php                  PhpFileLoader::load()               ↓
Extension::load()             Extension::load()            ContainerBuilder
                              |                             (definitions + aliases
                              v                              + parameters)
                     Compiler::compile()              --->  最適化済みContainer
                              |
                              v
                     PhpDumper::dump()                --->  Container.php
                              |                             (コンパイル済みPHP)
                              v
                     Container::get(serviceId)        --->  サービスインスタンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Container.php | `src/Symfony/Component/DependencyInjection/Container.php` | ソース | ランタイムDIコンテナ |
| ContainerBuilder.php | `src/Symfony/Component/DependencyInjection/ContainerBuilder.php` | ソース | ビルド時DIコンテナ |
| ContainerInterface.php | `src/Symfony/Component/DependencyInjection/ContainerInterface.php` | ソース | コンテナインターフェース |
| Definition.php | `src/Symfony/Component/DependencyInjection/Definition.php` | ソース | サービス定義 |
| ChildDefinition.php | `src/Symfony/Component/DependencyInjection/ChildDefinition.php` | ソース | 子サービス定義 |
| Alias.php | `src/Symfony/Component/DependencyInjection/Alias.php` | ソース | サービスエイリアス |
| Reference.php | `src/Symfony/Component/DependencyInjection/Reference.php` | ソース | サービス参照 |
| TypedReference.php | `src/Symfony/Component/DependencyInjection/TypedReference.php` | ソース | 型付きサービス参照 |
| Parameter.php | `src/Symfony/Component/DependencyInjection/Parameter.php` | ソース | パラメータ参照 |
| Variable.php | `src/Symfony/Component/DependencyInjection/Variable.php` | ソース | 変数参照 |
| ServiceLocator.php | `src/Symfony/Component/DependencyInjection/ServiceLocator.php` | ソース | サービスロケーター |
| ReverseContainer.php | `src/Symfony/Component/DependencyInjection/ReverseContainer.php` | ソース | 逆引きコンテナ |
| EnvVarProcessor.php | `src/Symfony/Component/DependencyInjection/EnvVarProcessor.php` | ソース | 環境変数プロセッサー |
| ExpressionLanguage.php | `src/Symfony/Component/DependencyInjection/ExpressionLanguage.php` | ソース | 式言語統合 |
| Compiler/ | `src/Symfony/Component/DependencyInjection/Compiler/` | ソース | コンパイラパス群 |
| Loader/ | `src/Symfony/Component/DependencyInjection/Loader/` | ソース | サービス定義ローダー群 |
| Dumper/ | `src/Symfony/Component/DependencyInjection/Dumper/` | ソース | コンテナダンパー群 |
| ParameterBag/ | `src/Symfony/Component/DependencyInjection/ParameterBag/` | ソース | パラメータバッグ |
| Argument/ | `src/Symfony/Component/DependencyInjection/Argument/` | ソース | 特殊引数型群 |
| Attribute/ | `src/Symfony/Component/DependencyInjection/Attribute/` | ソース | PHP属性定義群 |
| LazyProxy/ | `src/Symfony/Component/DependencyInjection/LazyProxy/` | ソース | レイジープロキシ |
| Extension/ | `src/Symfony/Component/DependencyInjection/Extension/` | ソース | バンドル拡張基底 |
| Config/ | `src/Symfony/Component/DependencyInjection/Config/` | ソース | 設定統合 |
| Exception/ | `src/Symfony/Component/DependencyInjection/Exception/` | ソース | 例外クラス群 |
