# Symfony 8.1 コードリーディングガイドライン

## はじめに

このガイドラインは、Symfony 8.1フレームワークのコードベースを効率的に理解するための手引きです。
PHPに精通していないエンジニアでも、段階的に学習できるよう構成されています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

---

## 1. 言語基礎

> このセクションでは、PHPの基本構文と概念を解説します。

### 1.1 プログラム構造

PHPファイルは `<?php` タグで始まります。Symfonyでは全ファイルが純粋なPHPコードであり、閉じタグ `?>` は使用しません。各ファイルの先頭にはライセンスコメントブロックが配置され、その後に `namespace` 宣言、`use` 文（インポート）、クラス定義が続きます。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:1-55
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\HttpKernel;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ... 他のuse文

class HttpKernel implements HttpKernelInterface, TerminableInterface
{
    // クラス本体
}
```

**ポイント:**
- `namespace` はファイルの論理的な所属先を宣言する（Java のパッケージに相当）
- `use` は他の名前空間のクラスをインポートする（Java/Python の import に相当）
- 1ファイル1クラスが基本原則（PSR-4オートロード規約）

### 1.2 データ型と変数

PHP 8.4以上を前提とし、強い型付けが積極的に活用されています。変数は `$` プレフィックスで始まります。

```php
// ファイル: src/Symfony/Component/HttpKernel/Kernel.php:54-68
abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface
{
    /**
     * @var array<string, BundleInterface>
     */
    protected array $bundles = [];

    protected ?ContainerInterface $container = null;
    protected bool $booted = false;
    protected ?float $startTime = null;

    private string $projectDir;
    private ?string $warmupDir = null;
    private int $requestStackSize = 0;
    private bool $resetServices = false;
}
```

**主要な型宣言:**
- `string`, `int`, `float`, `bool` -- スカラー型
- `array` -- 配列型（PHPDoc `@var array<key, value>` で詳細型を記述）
- `?Type` -- Nullable型（null許容）
- `Type|false` -- Union型（PHP 8.0以降）
- `protected`, `private`, `public` -- アクセス修飾子

### 1.3 制御構造

条件分岐やループはC言語系の構文を踏襲しています。Symfonyでは`match`式やNull合体演算子`??`も頻用されます。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:72-94
public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
{
    $request->headers->set('X-Php-Ob-Level', (string) ob_get_level());

    $this->requestStack->push($request);
    $response = null;
    try {
        return $response = $this->handleRaw($request, $type, $controllerMetadata);
    } catch (\Throwable $e) {
        if ($e instanceof \Error && !$this->handleAllThrowables) {
            throw $e;
        }

        if ($e instanceof RequestExceptionInterface) {
            $e = new BadRequestHttpException($e->getMessage(), $e);
        }
        if (false === $catch) {
            $this->finishRequest($request, $type, $controllerMetadata);
            throw $e;
        }

        return $response = $this->handleThrowable($e, $request, $type, $controllerMetadata);
    } finally {
        $this->requestStack->pop();
    }
}
```

**ポイント:**
- `try/catch/finally` -- 例外処理（Java と同様）
- `instanceof` -- 型チェック
- `\Throwable` -- PHP における全エラー/例外の基底インターフェース
- `===` / `!==` -- 厳密比較（型と値の両方を比較）

### 1.4 関数/メソッド定義

メソッドには戻り値型が宣言され、コンストラクタプロモーション（PHP 8.0以降）が多用されます。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:61-70
public function __construct(
    protected EventDispatcherInterface $dispatcher,
    protected ControllerResolverInterface $resolver,
    ?RequestStack $requestStack = null,
    ?ArgumentResolverInterface $argumentResolver = null,
    private bool $handleAllThrowables = false,
) {
    $this->requestStack = $requestStack ?? new RequestStack();
    $this->argumentResolver = $argumentResolver ?? new ArgumentResolver();
}
```

**ポイント:**
- `__construct` はコンストラクタメソッド（特殊メソッド）
- コンストラクタプロモーション: 引数に `protected`/`private` を付けると自動的にプロパティとして宣言される
- `??` -- Null合体演算子（左辺がnullの場合に右辺の値を使用）
- 末尾カンマ: 引数リストの最後にカンマを許容する（PHP 8.0以降）

### 1.5 モジュール/インポート

PHPの名前空間とComposerのPSR-4オートロードにより、ファイルパスと名前空間が1対1で対応します。

```php
// ファイル: src/Symfony/Component/EventDispatcher/EventDispatcher.php:12-16
namespace Symfony\Component\EventDispatcher;

use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Debug\WrappedListener;
```

**名前空間とディレクトリの対応関係（composer.json の autoload 定義）:**

| 名前空間プレフィックス | ディレクトリ |
|----------------------|-------------|
| `Symfony\Bridge\Doctrine\` | `src/Symfony/Bridge/Doctrine/` |
| `Symfony\Bridge\Monolog\` | `src/Symfony/Bridge/Monolog/` |
| `Symfony\Bridge\Twig\` | `src/Symfony/Bridge/Twig/` |
| `Symfony\Bundle\` | `src/Symfony/Bundle/` |
| `Symfony\Component\` | `src/Symfony/Component/` |

---

## 2. プロジェクト固有の概念

> このセクションでは、Symfony 8.1 特有の概念を解説します。

### 2.1 フレームワーク固有の概念

#### PHP Attributes（アトリビュート）

PHP 8.0以降の機能である「Attribute」が、Symfony 8.1ではDIコンテナ設定、ルーティング、コマンド登録、イベントリスナー登録など多岐にわたって活用されています。`#[...]` 構文で記述し、従来のXML/YAML設定を置き換えます。

```php
// ファイル: src/Symfony/Component/Console/Attribute/AsCommand.php:17-18
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
final class AsCommand
{
    public function __construct(
        public string $name,
        public ?string $description = null,
        // ...
    ) {
    }
}
```

```php
// ファイル: src/Symfony/Component/EventDispatcher/Attribute/AsEventListener.php:19-35
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class AsEventListener
{
    public function __construct(
        public ?string $event = null,
        public ?string $method = null,
        public int $priority = 0,
        public ?string $dispatcher = null,
    ) {
    }
}
```

**主要なAttribute一覧:**

| Attribute | 所属コンポーネント | 用途 |
|-----------|-------------------|------|
| `#[AsCommand]` | Console | コンソールコマンドの自動登録 |
| `#[AsEventListener]` | EventDispatcher | イベントリスナーの自動登録 |
| `#[AsMessageHandler]` | Messenger | メッセージハンドラの自動登録 |
| `#[Route]` | Routing | ルート定義 |
| `#[Autowire]` | DependencyInjection | DI時の注入設定 |
| `#[AutowireLocator]` | DependencyInjection | サービスロケータの注入 |
| `#[When]` / `#[WhenNot]` | DependencyInjection | 条件付きサービス登録 |

#### Kernel（カーネル）

Symfonyアプリケーションの中心的なクラスです。`Kernel` クラスはバンドルの管理、DIコンテナの構築、リクエスト処理を統括します。

```php
// ファイル: src/Symfony/Component/HttpKernel/Kernel.php:53-54
abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface
```

#### Bundle（バンドル）

機能をモジュール化するための仕組みです。バンドルはDIコンテナの拡張、コンパイラパスの登録などを行います。

```php
// ファイル: src/Symfony/Component/HttpKernel/Bundle/Bundle.php:25-48
abstract class Bundle implements BundleInterface
{
    public function boot(): void {}
    public function shutdown(): void {}
    public function build(ContainerBuilder $container): void {}
}
```

#### DI Container（依存性注入コンテナ）

`ContainerBuilder` はサービスの定義、エイリアス、タグ付けを管理し、コンパイル時にサービスの依存関係を解決します。

```php
// ファイル: src/Symfony/Component/DependencyInjection/ContainerBuilder.php:59
class ContainerBuilder extends Container implements TaggedContainerInterface
{
    private array $extensions = [];
    private array $definitions = [];
    private array $aliasDefinitions = [];
}
```

### 2.2 プロジェクト独自のパターン

#### opcache.preload の最適化ヒント

頻繁に使用されるクラスに対して、ファイル冒頭で `class_exists()` を呼び出すことで、opcacheのプリロード時にシンボルを事前に発見させる最適化パターンが採用されています。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:38-48
// Help opcache.preload discover always-needed symbols
class_exists(ControllerArgumentsEvent::class);
class_exists(ControllerEvent::class);
class_exists(ExceptionEvent::class);
class_exists(RequestEvent::class);
class_exists(ResponseEvent::class);
```

#### PSR準拠のインターフェース提供

Symfonyは複数のPSR（PHP Standards Recommendation）に準拠したインターフェースを実装・提供しています。

| PSR | 概要 | Symfony実装 |
|-----|------|-------------|
| PSR-4 | オートロード | Composer autoload |
| PSR-6 / PSR-16 | キャッシュ | Cache コンポーネント |
| PSR-7 | HTTPメッセージ | PsrHttpMessage Bridge |
| PSR-11 | コンテナ | DependencyInjection |
| PSR-14 | イベントディスパッチャー | EventDispatcher |
| PSR-15 | HTTPハンドラ | HttpKernel |
| PSR-20 | クロック | Clock コンポーネント |

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `PascalCase.php` | クラスファイル（1ファイル1クラス） | `HttpKernel.php`, `EventDispatcher.php` |
| `*Interface.php` | インターフェース定義 | `HttpKernelInterface.php`, `ControllerResolverInterface.php` |
| `*Trait.php` | トレイト（再利用可能なメソッド群） | `HandleTrait.php` |
| `*Exception.php` | 例外クラス | `NotFoundHttpException.php` |
| `Abstract*.php` | 抽象クラス | `AbstractObjectNormalizer.php` |
| `*Pass.php` | コンパイラパス | `ProfilerPass.php`, `CachePoolPass.php` |
| `*Event.php` | イベントクラス | `RequestEvent.php`, `ResponseEvent.php` |
| `*Test.php` | テストクラス（Tests/ディレクトリ配下） | `HttpKernelTest.php` |
| `Bridge/` | 外部ライブラリとの統合層 | `Bridge/Doctrine/`, `Bridge/Twig/` |
| `Bundle/` | バンドル（アプリケーション機能パッケージ） | `Bundle/FrameworkBundle/` |
| `Component/` | 再利用可能な独立コンポーネント | `Component/HttpKernel/` |
| `Attribute/` | PHP Attributeクラス群 | `Attribute/AsCommand.php` |
| `DependencyInjection/` | DI拡張・コンパイラパス | `DependencyInjection/` |
| `Resources/` | 設定ファイル、テンプレート、翻訳 | `Resources/config/` |
| `Tests/` | テストコード | `Tests/` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `Interface` サフィックス | インターフェース | `HttpKernelInterface`, `MessageBusInterface` |
| `Abstract` プレフィックス | 抽象基底クラス | `AbstractObjectNormalizer` |
| `*Aware` サフィックス | 特定オブジェクトの注入を受けるインターフェース | `NormalizerAwareInterface` |
| `*Extension` サフィックス | DI拡張クラス | `FrameworkExtension` |
| `*Pass` サフィックス | DIコンパイラパス | `RegisterListenersPass` |
| `As*` プレフィックス（Attribute） | 自動設定用Attribute | `AsCommand`, `AsEventListener`, `AsMessageHandler` |
| `*Resolver` サフィックス | 解決処理クラス | `ControllerResolver`, `ArgumentResolver` |
| `*Loader` サフィックス | 設定読み込みクラス | `YamlFileLoader`, `PhpFileLoader` |
| `*Dumper` サフィックス | データ出力/エクスポートクラス | `PhpDumper`, `CompiledUrlMatcherDumper` |
| `*Voter` サフィックス | セキュリティ投票者 | `RoleVoter` |
| `*Normalizer`/`*Encoder` | シリアライズ関連 | `ObjectNormalizer`, `JsonEncoder` |
| `$camelCase` | 変数名（キャメルケース） | `$requestStack`, `$middlewareAggregate` |
| `UPPER_SNAKE_CASE` | 定数 | `MAIN_REQUEST`, `HTTP_OK` |

### 3.3 プログラム分類一覧

| 分類 | 名前空間プレフィックス | 説明 |
|------|----------------------|------|
| Bridge | `Symfony\Bridge\*` | 外部ライブラリ（Doctrine, Twig, Monolog）との統合 |
| Bundle | `Symfony\Bundle\*` | フルスタック機能のパッケージ |
| Component | `Symfony\Component\*` | 独立して利用可能な再利用コンポーネント |
| Contracts | `Symfony\Contracts\*` | 抽象インターフェース・共通契約 |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
symfony-8.1/
├── composer.json              # 依存関係定義・オートロード設定
├── phpunit.xml.dist           # PHPUnit設定
├── psalm.xml                  # 静的解析ツール設定
├── LICENSE                    # MITライセンス
├── README.md                  # プロジェクト概要
├── CHANGELOG-8.0.md           # 変更履歴
├── UPGRADE-8.0.md             # アップグレードガイド
├── UPGRADE-8.1.md             # アップグレードガイド
├── CONTRIBUTING.md            # 貢献ガイド
├── CONTRIBUTORS.md            # 貢献者一覧
├── splitsh.json               # サブリポジトリ分割設定
└── src/
    └── Symfony/
        ├── Bridge/            # 外部ライブラリ統合
        │   ├── Doctrine/      # Doctrine ORM統合
        │   ├── Monolog/       # Monologロギング統合
        │   ├── PsrHttpMessage/# PSR-7 HTTPメッセージ統合
        │   └── Twig/          # Twigテンプレートエンジン統合
        ├── Bundle/            # バンドル（アプリケーション機能パッケージ）
        │   ├── DebugBundle/         # デバッグ機能
        │   ├── FrameworkBundle/     # コア機能バンドル
        │   ├── SecurityBundle/      # セキュリティ機能
        │   ├── TwigBundle/          # Twig統合バンドル
        │   ├── WebProfilerBundle/   # ウェブプロファイラー
        │   └── FullStack.php        # フルスタックマーカー
        ├── Component/         # 独立コンポーネント群
        │   ├── Asset/               # アセット管理
        │   ├── AssetMapper/         # アセットマッパー
        │   ├── BrowserKit/          # ブラウザシミュレーション
        │   ├── Cache/               # キャッシュ
        │   ├── Clock/               # 時刻抽象化（PSR-20）
        │   ├── Config/              # 設定管理
        │   ├── Console/             # CLIコマンド
        │   ├── CssSelector/         # CSS→XPath変換
        │   ├── DependencyInjection/ # DIコンテナ
        │   ├── DomCrawler/          # DOM操作
        │   ├── Dotenv/              # 環境変数管理
        │   ├── Emoji/               # 絵文字処理
        │   ├── ErrorHandler/        # エラーハンドリング
        │   ├── EventDispatcher/     # イベントシステム
        │   ├── ExpressionLanguage/  # 式言語
        │   ├── Filesystem/          # ファイルシステム操作
        │   ├── Finder/              # ファイル検索
        │   ├── Form/                # フォーム処理
        │   ├── HtmlSanitizer/       # HTMLサニタイズ
        │   ├── HttpClient/          # HTTPクライアント
        │   ├── HttpFoundation/      # HTTPリクエスト/レスポンス
        │   ├── HttpKernel/          # HTTPカーネル（リクエスト処理の中核）
        │   ├── Intl/                # 国際化
        │   ├── JsonPath/            # JSONパスクエリ
        │   ├── JsonStreamer/        # JSONストリーミング
        │   ├── Ldap/                # LDAP統合
        │   ├── Lock/                # ロック機構
        │   ├── Mailer/              # メール送信
        │   ├── Messenger/           # メッセージバス/非同期処理
        │   ├── Mime/                # MIMEメッセージ構築
        │   ├── Notifier/            # 通知システム
        │   ├── ObjectMapper/        # オブジェクトマッピング
        │   ├── OptionsResolver/     # オプション解決
        │   ├── PasswordHasher/      # パスワードハッシュ
        │   ├── Process/             # プロセス実行
        │   ├── PropertyAccess/      # プロパティアクセス
        │   ├── PropertyInfo/        # プロパティ情報
        │   ├── RateLimiter/         # レート制限
        │   ├── RemoteEvent/         # リモートイベント
        │   ├── Routing/             # ルーティング
        │   ├── Scheduler/           # スケジューラー
        │   ├── Security/            # セキュリティ（Core/Csrf/Http）
        │   ├── Semaphore/           # セマフォ
        │   ├── Serializer/          # シリアライゼーション
        │   ├── Stopwatch/           # パフォーマンス計測
        │   ├── String/              # 文字列操作
        │   ├── Translation/         # 翻訳
        │   ├── TypeInfo/            # 型情報
        │   ├── Uid/                 # UUID/ULID生成
        │   ├── Validator/           # バリデーション
        │   ├── VarDumper/           # デバッグダンプ
        │   ├── VarExporter/         # 変数エクスポート
        │   ├── WebLink/             # Webリンク
        │   ├── Webhook/             # Webhook
        │   ├── Workflow/            # ワークフロー/ステートマシン
        │   └── Yaml/               # YAML解析
        └── Contracts/         # インターフェース契約
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `src/Symfony/Bridge/` | 外部ライブラリとSymfonyの橋渡し | `Doctrine/`, `Twig/`, `Monolog/` |
| `src/Symfony/Bundle/` | アプリケーション向けの機能パッケージ | `FrameworkBundle/FrameworkBundle.php` |
| `src/Symfony/Component/` | 独立して再利用可能なPHPライブラリ群 | 各コンポーネントの主要クラス |
| `src/Symfony/Component/HttpKernel/` | リクエスト→レスポンス変換の中核 | `Kernel.php`, `HttpKernel.php` |
| `src/Symfony/Component/HttpFoundation/` | HTTP抽象化（Request/Response） | `Request.php`, `Response.php` |
| `src/Symfony/Component/DependencyInjection/` | サービスの依存性注入コンテナ | `ContainerBuilder.php` |
| `src/Symfony/Component/EventDispatcher/` | イベント駆動アーキテクチャの実装 | `EventDispatcher.php` |
| `src/Symfony/Component/Routing/` | URLとコントローラーのマッピング | `Router.php`, `Route.php` |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

Symfonyは**コンポーネントベースのモジュラーアーキテクチャ**を採用しています。各コンポーネントは独立して利用可能であり、フルスタックフレームワークとして組み合わせて使用することもできます。HTTPリクエスト処理においては**イベント駆動アーキテクチャ**が中核にあり、`HttpKernel` がリクエストのライフサイクルをイベントとして管理します。

```mermaid
graph TB
    subgraph "HTTP Layer"
        REQ[HTTP Request] --> KERNEL[HttpKernel]
        KERNEL --> RES[HTTP Response]
    end

    subgraph "Event-Driven Pipeline"
        KERNEL --> E1[kernel.request]
        E1 --> E2[kernel.controller]
        E2 --> E3[kernel.controller_arguments]
        E3 --> CTRL[Controller Execution]
        CTRL --> E4[kernel.view]
        E4 --> E5[kernel.response]
        E5 --> E6[kernel.finish_request]
        E5 --> E7[kernel.terminate]
    end

    subgraph "Core Services"
        DI[DI Container] --> KERNEL
        ED[EventDispatcher] --> KERNEL
        RT[Router] --> E1
    end

    subgraph "Exception Handling"
        KERNEL --> E8[kernel.exception]
    end
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| HTTP層 | HTTPリクエスト/レスポンスの抽象化 | `HttpFoundation/Request.php`, `HttpFoundation/Response.php` |
| カーネル層 | リクエスト処理パイプライン | `HttpKernel/HttpKernel.php`, `HttpKernel/Kernel.php` |
| イベント層 | リクエストライフサイクルのフック | `HttpKernel/KernelEvents.php`, `EventDispatcher/EventDispatcher.php` |
| ルーティング層 | URLとコントローラーのマッピング | `Routing/Router.php`, `Routing/Attribute/Route.php` |
| DI層 | サービスの構築と依存性解決 | `DependencyInjection/ContainerBuilder.php` |
| バンドル層 | 機能のモジュール化 | `HttpKernel/Bundle/Bundle.php`, `Bundle/FrameworkBundle/` |
| ビジネスロジック層 | ユーザー定義のビジネスロジック | コントローラー、サービスクラス |
| 永続化層 | データアクセス | `Bridge/Doctrine/` |

### 5.3 データフロー

Symfonyのリクエスト処理は以下の順序で進行します。

1. **ブートストラップ**: `Kernel::boot()` でDIコンテナを初期化し、全バンドルをブート
2. **リクエスト受信**: `Kernel::handle()` がHTTPリクエストを受け取る
3. **イベントパイプライン**: `HttpKernel::handleRaw()` で各イベントを順次ディスパッチ
4. **ルーティング**: `kernel.request` イベントでRouterがURLをマッチングし、コントローラーを特定
5. **コントローラー実行**: コントローラーが呼び出され、Responseを返却
6. **レスポンス後処理**: `kernel.response` イベントでレスポンスの加工
7. **ターミネート**: `kernel.terminate` イベントで非同期的な後処理

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

アプリケーションの起動は `Kernel` クラスの `handle()` メソッドから始まります。

```php
// ファイル: src/Symfony/Component/HttpKernel/Kernel.php:167-179
public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
{
    if (!$this->container) {
        $this->preBoot();
    }

    if (HttpKernelInterface::MAIN_REQUEST === $type && !$this->handlingHttpCache && $this->container->has('http_cache')) {
        $this->handlingHttpCache = true;
        try {
            return $this->container->get('http_cache')->handle($request, $type, $catch);
        } finally {
            $this->handlingHttpCache = false;
        }
    }
    // ...
}
```

`HttpKernel::handle()` が実際のリクエスト処理パイプラインを実行します。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernelInterface.php:22-40
interface HttpKernelInterface
{
    public const MAIN_REQUEST = 1;
    public const SUB_REQUEST = 2;

    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response;
}
```

### 6.2 ビジネスロジック

#### イベント駆動パイプライン

`HttpKernel::handleRaw()` はリクエスト処理の中核であり、以下のイベントを順に発火します。

```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:158-188
private function handleRaw(Request $request, int $type = self::MAIN_REQUEST, ?ControllerMetadata &$controllerMetadata = null): Response
{
    // 1. kernel.request イベント（ルーティング解決など）
    $event = new RequestEvent($this, $request, $type);
    $this->dispatcher->dispatch($event, KernelEvents::REQUEST);

    // 2. コントローラーの解決
    if (false === $controller = $this->resolver->getController($request)) {
        throw new NotFoundHttpException(...);
    }

    // 3. kernel.controller イベント
    $controllerEvent = new ControllerEvent($this, $controller, $request, $type);
    $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER);
    $controller = $event->getController();

    // 4. 引数解決 + kernel.controller_arguments イベント
    $arguments = $this->argumentResolver->getArguments($request, $controller, $event->getControllerReflector());
    $event = new ControllerArgumentsEvent($this, $event, $arguments, $request, $type);
    $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS);

    // 5. コントローラー実行
    $response = $controller(...$arguments);

    // 6. kernel.view イベント（Responseでない場合）
    // 7. kernel.response イベント
}
```

#### イベント定数

```php
// ファイル: src/Symfony/Component/HttpKernel/KernelEvents.php:29-111
final class KernelEvents
{
    public const REQUEST = 'kernel.request';              // リクエスト受信時
    public const EXCEPTION = 'kernel.exception';          // 例外発生時
    public const CONTROLLER = 'kernel.controller';        // コントローラー決定時
    public const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments'; // 引数解決時
    public const VIEW = 'kernel.view';                    // Responseでない戻り値の変換時
    public const RESPONSE = 'kernel.response';            // レスポンス送信前
    public const FINISH_REQUEST = 'kernel.finish_request';// リクエスト処理完了時
    public const TERMINATE = 'kernel.terminate';          // レスポンス送信後
}
```

#### EventDispatcher

イベントの登録・ディスパッチを管理する中央システムです。

```php
// ファイル: src/Symfony/Component/EventDispatcher/EventDispatcher.php:45-60
public function dispatch(object $event, ?string $eventName = null): object
{
    $eventName ??= $event::class;

    if (isset($this->optimized)) {
        $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
    } else {
        $listeners = $this->getListeners($eventName);
    }

    if ($listeners) {
        $this->callListeners($listeners, $eventName, $event);
    }

    return $event;
}
```

### 6.3 データアクセス

Symfonyのデータアクセスは主に `Bridge/Doctrine` を通じて Doctrine ORM と統合されます。Symfony自体にはORM機能は含まれず、Bridge層がSymfonyのDIコンテナやイベントシステムとDoctrineを接続します。

また、`Serializer` コンポーネントはオブジェクトとデータフォーマット間の変換を担います。

```php
// ファイル: src/Symfony/Component/Serializer/Serializer.php:46
class Serializer implements SerializerInterface, NormalizerInterface, DenormalizerInterface, ContextAwareEncoderInterface, ContextAwareDecoderInterface
```

Serializerは2段階の処理パイプラインを持ちます:
1. **Normalizer**: オブジェクト → 配列（正規化）
2. **Encoder**: 配列 → JSON/XML/CSV（エンコード）

### 6.4 ユーティリティ/共通機能

#### Messenger（メッセージバス）

非同期処理・CQRS パターンをサポートするメッセージバスシステムです。

```php
// ファイル: src/Symfony/Component/Messenger/MessageBus.php:22-61
class MessageBus implements MessageBusInterface
{
    private \IteratorAggregate $middlewareAggregate;

    public function dispatch(object $message, array $stamps = []): Envelope
    {
        $envelope = Envelope::wrap($message, $stamps);
        $middlewareIterator = $this->middlewareAggregate->getIterator();
        // ミドルウェアチェーンを通じてメッセージを処理
    }
}
```

#### Console（コンソールコマンド）

CLIコマンドの基底クラスです。

```php
// ファイル: src/Symfony/Component/Console/Command/Command.php:35-39
class Command implements SignalableCommandInterface
{
    public const SUCCESS = 0;
    public const FAILURE = 1;
    public const INVALID = 2;
}
```

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| イベントディスパッチ | イベント経由での処理フック | 高 | `HttpKernel/HttpKernel.php` |
| コンパイラパス | DIコンテナビルド時の拡張 | 高 | `Bundle/FrameworkBundle/FrameworkBundle.php` |
| PHP Attribute | 宣言的設定 | 高 | `Attribute/AsCommand.php`, `Attribute/Route.php` |
| ミドルウェアパイプライン | 処理の連鎖 | 中 | `Messenger/MessageBus.php` |
| インターフェース+実装分離 | 疎結合設計 | 高 | `HttpKernelInterface.php`, `HttpKernel.php` |
| Normalizer/Encoder分離 | 変換の段階的処理 | 中 | `Serializer/Serializer.php` |

### 各パターンの詳細

#### パターン1: イベントディスパッチ

**目的:** リクエスト処理パイプラインの各段階にフックポイントを提供し、疎結合な拡張を可能にする

**実装例:**
```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:161-162
$event = new RequestEvent($this, $request, $type);
$this->dispatcher->dispatch($event, KernelEvents::REQUEST);
```

**解説:** `EventDispatcher::dispatch()` を呼び出すと、そのイベント名に登録された全てのリスナーが優先度順に実行されます。リスナーはイベントオブジェクトを介して処理結果を返却したり、イベントの伝播を停止したりできます。

#### パターン2: コンパイラパス

**目的:** DIコンテナのビルド時にサービス定義を動的に変更する

**実装例:**
```php
// ファイル: src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php:46-48
// FrameworkBundleのbuild()メソッド内で多数のコンパイラパスを登録
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
$container->addCompilerPass(new ProfilerPass());
$container->addCompilerPass(new RegisterListenersPass());
```

**解説:** コンパイラパスはDIコンテナが「コンパイル」される際に実行されるフックです。特定のタグ付きサービスを収集して別のサービスに注入する、サービス定義を書き換えるなどの処理を行います。

#### パターン3: PHP Attribute による宣言的設定

**目的:** XMLやYAMLの設定ファイルを不要にし、コードに近い場所で設定を宣言する

**実装例:**
```php
// ファイル: src/Symfony/Component/Routing/Attribute/Route.php:18-52
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
class Route
{
    public function __construct(
        public string|array|null $path = null,
        public ?string $name = null,
        public array $requirements = [],
        public array $defaults = [],
        public ?string $host = null,
        array|string $methods = [],
        // ...
    ) {
    }
}
```

**解説:** `#[Route('/api/users', methods: ['GET'])]` のようにコントローラーメソッドに直接付与することで、そのメソッドがどのURLパスに対応するかを宣言できます。DI拡張やコンパイラパスがこれらのAttributeを読み取り、サービス定義に反映します。

#### パターン4: インターフェース+実装分離

**目的:** 依存の方向を抽象に向け、実装の差し替えを容易にする

**実装例:**
```php
// ファイル: src/Symfony/Component/HttpKernel/HttpKernelInterface.php:22-40
interface HttpKernelInterface
{
    public const MAIN_REQUEST = 1;
    public const SUB_REQUEST = 2;

    public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response;
}

// ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:55
class HttpKernel implements HttpKernelInterface, TerminableInterface
{
    // 実装
}
```

**解説:** Symfony全体で一貫して「Interface」サフィックスのインターフェースと、その具象実装クラスが分離されています。これによりDIコンテナ経由で実装を差し替えることが容易になり、テスト時のモック化も簡便になります。

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定（`Kernel::handle()`）
2. 処理の流れを追跡（イベントの発火順序を辿る）
3. データの変換を確認（Request → Controller → Response）
4. 最終的な出力を確認（HTTP Response）

### 8.2 フロー追跡の実例

#### 例1: HTTPリクエストの処理フロー

**概要:** ブラウザからのHTTPリクエストが、Symfony内部でどのように処理されてHTTPレスポンスになるかを追跡する

**処理フロー:**
```
HTTP Request → Kernel::handle() → HttpKernel::handle() → handleRaw() → [Events Pipeline] → Response
```

**詳細な追跡:**

1. **Kernel::handle() -- リクエスト受付** (`src/Symfony/Component/HttpKernel/Kernel.php:167`)
   ```php
   public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
   {
       if (!$this->container) {
           $this->preBoot();
       }
       // HTTPキャッシュがあればそちらに委譲、なければHttpKernelに委譲
   }
   ```

2. **HttpKernel::handle() -- パイプライン開始** (`src/Symfony/Component/HttpKernel/HttpKernel.php:72`)
   ```php
   public function handle(Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response
   {
       $this->requestStack->push($request);
       try {
           return $response = $this->handleRaw($request, $type, $controllerMetadata);
       } catch (\Throwable $e) {
           return $response = $this->handleThrowable($e, $request, $type, $controllerMetadata);
       } finally {
           $this->requestStack->pop();
       }
   }
   ```

3. **kernel.request イベント -- ルーティング解決** (`src/Symfony/Component/HttpKernel/HttpKernel.php:161-162`)
   ```php
   $event = new RequestEvent($this, $request, $type);
   $this->dispatcher->dispatch($event, KernelEvents::REQUEST);
   ```
   このイベントでRouterリスナーがURLをマッチングし、`$request->attributes` にコントローラー情報を設定します。

4. **コントローラー解決** (`src/Symfony/Component/HttpKernel/HttpKernel.php:169`)
   ```php
   if (false === $controller = $this->resolver->getController($request)) {
       throw new NotFoundHttpException(...);
   }
   ```

5. **kernel.controller / kernel.controller_arguments イベント** (`src/Symfony/Component/HttpKernel/HttpKernel.php:173-185`)
   ```php
   $controllerEvent = new ControllerEvent($this, $controller, $request, $type);
   $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER);

   $arguments = $this->argumentResolver->getArguments($request, $controller, ...);
   $event = new ControllerArgumentsEvent($this, $event, $arguments, $request, $type);
   $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS);
   ```

6. **コントローラー実行** (`src/Symfony/Component/HttpKernel/HttpKernel.php:188`)
   ```php
   $response = $controller(...$arguments);
   ```

7. **kernel.response / kernel.terminate** -- 後処理
   ```php
   // ファイル: src/Symfony/Component/HttpKernel/HttpKernel.php:113-121
   public function terminate(Request $request, Response $response): void
   {
       $this->dispatcher->dispatch(new TerminateEvent($this, $request, $response), KernelEvents::TERMINATE);
   }
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイントを特定したか（`Kernel::handle()`）
- [ ] 呼び出し関係を把握したか（`Kernel` → `HttpKernel` → `EventDispatcher`）
- [ ] データの変換ポイントを確認したか（Request → Controller引数 → Response）
- [ ] エラーハンドリングを確認したか（`kernel.exception` イベント、`handleThrowable()`）
- [ ] 最終的な出力を確認したか（`Response` オブジェクトのHTTP送信）

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `README.md` -- プロジェクト概要
2. `composer.json` -- 依存関係とコンポーネント一覧
3. `src/Symfony/Component/HttpKernel/Kernel.php` -- アプリケーションの中心
4. `src/Symfony/Component/HttpKernel/KernelEvents.php` -- リクエスト処理の全体像

#### 特定コンポーネントを理解したい場合
1. 該当コンポーネントの `README.md`
2. 該当コンポーネントの `CHANGELOG.md`
3. 該当コンポーネントの主要インターフェース（`*Interface.php`）
4. 主要な実装クラス

#### 改修作業を行う場合
1. `UPGRADE-8.1.md` -- 破壊的変更の確認
2. 対象コンポーネントの `CHANGELOG.md`
3. 対象コンポーネントのテストコード（`Tests/`）
4. 関連するBridge/Bundleへの影響確認

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `README.md` | プロジェクト概要 | 初回参加時 |
| `CONTRIBUTING.md` | 開発・貢献ルール | コード変更前 |
| `UPGRADE-8.0.md` / `UPGRADE-8.1.md` | バージョン間の破壊的変更 | バージョンアップ時 |
| `CHANGELOG-8.0.md` | 変更履歴 | 機能調査時 |
| 各コンポーネントの `README.md` | コンポーネント概要 | 特定機能の理解時 |
| 各コンポーネントの `CHANGELOG.md` | コンポーネントの変更履歴 | 変更内容の調査時 |
| `phpunit.xml.dist` | テスト設定 | テスト実行時 |
| `composer.json` | 依存関係・オートロード設定 | プロジェクト構造理解時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: `class_exists()` がファイル冒頭で呼ばれているが、これは何をしているのか？
A: opcache.preloadの最適化ヒントです。実行時の効果はなく、OPcacheのプリロード機能がこのファイルを処理する際に、関連クラスも同時にロードすることを促します。（参照: `src/Symfony/Component/HttpKernel/HttpKernel.php:38-48`）

#### Q: `#[\Attribute(...)]` の中の定数は何を意味するのか？
A: PHPのAttributeが適用可能な対象を制御します。
- `\Attribute::TARGET_CLASS` -- クラスに適用可能
- `\Attribute::TARGET_METHOD` -- メソッドに適用可能
- `\Attribute::TARGET_PARAMETER` -- パラメータに適用可能
- `\Attribute::IS_REPEATABLE` -- 同一対象に複数回適用可能

#### Q: `KernelEvents::REQUEST` と `RequestEvent::class` の関係は？
A: `KernelEvents::ALIASES` で定義されたマッピングにより、イベントクラス名をイベント名の代わりに使用できます。（参照: `src/Symfony/Component/HttpKernel/KernelEvents.php:118-127`）

#### Q: コンストラクタの引数に `protected` や `private` が付いているのはなぜか？
A: PHP 8.0以降の「コンストラクタプロモーション」機能です。引数宣言と同時にプロパティ宣言を行い、自動的に代入もされます。`$this->dispatcher = $dispatcher;` のようなボイラープレートコードが不要になります。

#### Q: 各コンポーネントに `composer.json` があるのはなぜか？
A: Symfonyのモノリポジトリ構造では、各コンポーネントが独立したComposerパッケージとしても公開されます。`splitsh.json` の設定により、各コンポーネントのサブディレクトリが独立リポジトリに分割されます。

### デバッグのヒント

- **イベントリスナーの特定**: `kernel.request` など特定イベントにどのリスナーが登録されているか調べるには、`EventDispatcher::getListeners()` メソッドの戻り値を確認する。FrameworkBundleの `debug:event-dispatcher` コマンドも有用。
- **DIコンテナの中身確認**: `debug:container` コマンドでサービス一覧を表示可能。
- **ルーティング確認**: `debug:router` コマンドで全ルート定義を表示可能。
- **コンパイラパスの追跡**: `FrameworkBundle.php` の `build()` メソッドを読むことで、どのコンパイラパスがどの順序で実行されるかを把握できる。

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| Bundle | Symfonyの機能をモジュール化する仕組み。DI拡張とルーティング設定をパッケージ化する |
| Component | Symfony内の独立した再利用可能なPHPライブラリ |
| Bridge | Symfonyと外部ライブラリ（Doctrine, Twigなど）を統合する薄いアダプター層 |
| Kernel | アプリケーションの中心。バンドルの管理とHTTPリクエスト処理を統括 |
| HttpKernel | Request→Response変換を行うイベント駆動パイプライン |
| DI Container | サービスの依存関係を管理し、自動的にインスタンスを構築する仕組み |
| Compiler Pass | DIコンテナのビルド時に実行されるフック。タグ付きサービスの収集などを行う |
| Event Dispatcher | オブザーバーパターンの実装。イベントの発火とリスナーの管理 |
| Middleware | メッセージバスにおける処理チェーンの各段階 |
| Stamp | Messengerコンポーネントでメッセージにメタデータを付与する仕組み |
| Envelope | Messengerコンポーネントでメッセージとスタンプをラップするオブジェクト |
| Normalizer | オブジェクトを配列に変換する（正規化） |
| Encoder | 配列をJSON/XML等のフォーマットに変換する |
| Attribute | PHP 8.0以降のメタデータ宣言機能。クラスやメソッドに構造化された設定を付与 |
| PSR | PHP Standards Recommendation。PHP-FIGが策定するPHPの標準仕様 |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `composer.json` | Composerパッケージ定義 | 依存関係、オートロード設定 |
| `phpunit.xml.dist` | PHPUnitテスト設定 | テストスイート定義 |
| `psalm.xml` | Psalm静的解析設定 | 型チェックの設定 |
| `splitsh.json` | サブリポジトリ分割設定 | コンポーネント別リポジトリへの分割定義 |
| `src/Symfony/Component/HttpKernel/Kernel.php` | 抽象カーネルクラス | アプリケーションブート、DIコンテナ構築 |
| `src/Symfony/Component/HttpKernel/HttpKernel.php` | HTTPカーネル実装 | リクエスト処理パイプライン |
| `src/Symfony/Component/HttpKernel/KernelEvents.php` | カーネルイベント定義 | 全HTTPイベント名の定数 |
| `src/Symfony/Component/HttpFoundation/Request.php` | HTTPリクエスト抽象化 | GET/POST/Cookie等のHTTP情報 |
| `src/Symfony/Component/HttpFoundation/Response.php` | HTTPレスポンス抽象化 | ステータスコード、ヘッダー、ボディ |
| `src/Symfony/Component/DependencyInjection/ContainerBuilder.php` | DIコンテナビルダー | サービス定義の登録とコンパイル |
| `src/Symfony/Component/EventDispatcher/EventDispatcher.php` | イベントディスパッチャー | イベントの発火とリスナー管理 |
| `src/Symfony/Component/Routing/Router.php` | ルーター | URLマッチングとURL生成 |
| `src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php` | フレームワークバンドル | コアサービスとコンパイラパスの登録 |
| `src/Symfony/Component/Console/Command/Command.php` | コマンド基底クラス | CLIコマンドの定義 |
| `src/Symfony/Component/Messenger/MessageBus.php` | メッセージバス | メッセージのディスパッチとミドルウェア処理 |
| `src/Symfony/Component/Serializer/Serializer.php` | シリアライザー | オブジェクトとデータフォーマット間の変換 |

### C. 参考資料

- [Symfony公式ドキュメント](https://symfony.com/doc/current/index.html)
- [Symfony コンポーネント一覧](https://symfony.com/components)
- [PHP 8.4 公式ドキュメント](https://www.php.net/manual/en/)
- [PSR標準仕様一覧](https://www.php-fig.org/psr/)
- [Composer ドキュメント](https://getcomposer.org/doc/)
- [Doctrine ORM ドキュメント](https://www.doctrine-project.org/projects/orm.html)
- [Twig テンプレートエンジン ドキュメント](https://twig.symfony.com/)
