# 帳票設計書 22-HTML変数ダンプ

## 概要

本ドキュメントは、Symfony VarDumperコンポーネントにおける `HtmlDumper` クラスの帳票設計書である。PHPの変数情報をインタラクティブなHTML形式で出力し、WebProfilerやデバッグツールバーで使用される機能について、出力仕様・処理フロー・データ構造を定義する。

### 本帳票の処理概要

`HtmlDumper` は、VarDumperコンポーネントのCloner（VarCloner）で取得されたData オブジェクトを、ブラウザ上で閲覧可能なインタラクティブHTML形式に変換するクラスである。CliDumperを継承し、HTML固有のスタイリング・展開/折りたたみ・検索機能を備えたリッチな変数表示を提供する。

**業務上の目的・背景**：開発時のデバッグにおいて、複雑なオブジェクト構造や大規模な配列の内容を効率的に把握する必要がある。HtmlDumperは、色分け・折りたたみ・検索といったインタラクティブな機能を備え、Web画面上での変数デバッグを大幅に効率化する。Symfonyの `dump()` 関数やWebProfilerの中核機能として使用される。

**帳票の利用シーン**：Webリクエスト処理中に `dump()` 関数が呼ばれた際、WebProfiler/デバッグツールバーでの変数表示、エラーページでの変数表示に使用される。

**主要な出力内容**：
1. HTML `<pre>` タグで囲まれた変数ダンプ出力
2. CSSスタイル定義（darkテーマ/lightテーマ対応）
3. JavaScriptによるインタラクティブ機能（展開/折りたたみ、検索、ハイライト）
4. ANSIカラーコードの代わりにCSSクラスベースのスタイリング
5. 画像データのインライン表示（Base64エンコード）

**帳票の出力タイミング**：`dump()` ヘルパー関数の呼び出し時、WebProfilerのレンダリング時、HtmlErrorRendererでの変数表示時に出力される。

**帳票の利用者**：アプリケーション開発者、フロントエンド開発者、QAエンジニア

## 帳票種別

デバッグ情報ダンプ（HTML出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | WebProfiler | `/_profiler/{token}` | 自動表示 |
| - | デバッグツールバー | 任意のURL | `dump()` 関数呼び出し |
| - | エラーページ | 任意のURL（例外発生時） | 自動表示 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | HTML（インライン出力） |
| 用紙サイズ | N/A（Web画面出力） |
| 向き | N/A |
| ファイル名 | N/A（HTTPレスポンスに埋め込み） |
| 出力方法 | HTMLインライン出力 / 文字列返却 |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

HTML形式の変数ダンプ出力は、`<pre>` タグ内にスタイル付きの `<span>` タグでネストされた構造を持つ。初回出力時にはJavaScriptとCSSのヘッダーが付与される。

```
┌──────────────────────────────────────────┐
│  <style> CSSテーマ定義 </style>           │
│  <script> Sfdump JS関数 </script>         │
├──────────────────────────────────────────┤
│  <pre class="sf-dump" id="sf-dump-xxx">  │
│    検索バー（JS有効時表示）                 │
│    ルートオブジェクト/配列                  │
│      ├─ プロパティ1: 値                   │
│      ├─ プロパティ2: {                    │
│      │     ├─ 子プロパティ ...            │
│      │     └─ ...                        │
│      └─ ...                              │
│  </pre>                                  │
│  <script>Sfdump("sf-dump-xxx")</script>  │
└──────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | CSS定義 | テーマに応じたスタイルシート | `static::$themes` 配列 | `<style>` タグ |
| 2 | JavaScript | インタラクティブ機能（toggle/search） | `getDumpHeader()` メソッド内のインラインJS | `<script>` タグ |
| 3 | 表示オプション | maxDepth, maxStringLength, fileLinkFormat | `$displayOptions` 配列 | JSONとしてJS内に埋め込み |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | 変数型 | オブジェクト名/配列/スカラー型 | `Data` オブジェクト | `<span class="sf-dump-note">` | 可変 |
| 2 | プロパティ名 | オブジェクトプロパティまたは配列キー | `Cursor::hashKey` | `<span class="sf-dump-public/protected/private">` | 可変 |
| 3 | 値 | 各プロパティの値 | `Data` オブジェクトの各要素 | 型に応じたCSSクラス | 可変 |
| 4 | 参照情報 | オブジェクト参照（#id） | `Cursor::softRefHandle` | `<a class="sf-dump-ref" href="#sf-dump-xxx-refXXX">` | 可変 |
| 5 | 画像データ | インライン画像表示 | `cursor->attr['img-data']` | `<img src="data:...;base64,...">` | max 50em |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 初期化スクリプト | Sfdump関数の呼び出し | dumpIdとdisplayOptions | `<script>Sfdump("sf-dump-xxx")</script>` |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| Dataオブジェクト | VarClonerで取得された変数データ | Yes |
| 出力先 | callable/resource/string/null | No（デフォルト: php://output） |
| extraDisplayOptions | 追加表示オプション | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | プロパティ定義順 | 定義順（Cloner取得順） |

### 改ページ条件

該当なし（Web出力のため改ページ概念なし。`maxDepth` による折りたたみで表示量を制御）

## データベース参照仕様

### 参照テーブル一覧

該当なし（メモリ内のPHP変数をダンプする機能のため、データベースを参照しない）

### テーブル別参照項目詳細

該当なし

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ダンプID | `'sf-dump-' . mt_rand()` | なし | 各ダンプ出力のユニークID |
| 文字列長表示 | `mb_strlen($str, 'UTF-8') + $cut` | なし | 切り詰め前の元文字列長 |
| 参照ID | `{refType}{softRefHandle or refIndex}` | なし | オブジェクト/リソース参照の識別子 |
| HTML数値エンティティ | `mb_encode_numericentity($line, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8')` | なし | 非ASCII文字のHTMLエンティティ変換 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[dump Data呼び出し] --> B[extraDisplayOptions設定]
    B --> C[親クラスdump呼び出し]
    C --> D{ヘッダー出力済み?}
    D -->|No| E[getDumpHeader: CSS+JS出力]
    D -->|Yes| F[dumpPrefix出力]
    E --> F
    F --> G[Data::dump で各要素走査]
    G --> H{要素タイプ}
    H -->|Scalar| I[dumpScalar: スカラー値出力]
    H -->|String| J[dumpString: 文字列出力]
    H -->|Hash| K[enterHash/leaveHash: 構造体出力]
    I --> L[style メソッドでHTML装飾]
    J --> L
    K --> L
    L --> M[dumpLine: 行出力+HTMLエンティティ変換]
    M --> N[dumpSuffix: 初期化スクリプト出力]
    N --> O[dumpId更新]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| テーマ不存在 | setTheme()に存在しないテーマ名を指定 | `Theme "%s" does not exist in class "%s".` (InvalidArgumentException) | dark/lightのいずれかを指定 |
| 出力エラー | 出力先ストリームへの書き込み失敗 | PHP Warning | 有効な出力先を指定 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千プロパティ（maxDepthで制御） |
| 目標出力時間 | 50ms以内（デバッグツールバー応答性） |
| 同時出力数上限 | 制限なし（ページ内に複数ダンプ可能） |

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

- ダンプ出力には変数の全内容が含まれるため、本番環境では必ず無効化すること
- パスワード、APIキー、トークン等の機密情報がダンプ出力に含まれる可能性がある
- `fileLinkFormat` によりローカルファイルパスが露出する可能性がある
- HTML出力は `htmlspecialchars()` でエスケープされるため、XSS対策済み

## 備考

- CliDumperを継承し、HTML固有の装飾をオーバーライドで実装
- darkテーマ（デフォルト）とlightテーマの2種類を標準提供
- JavaScriptが無効な環境でも基本的な表示は可能（折りたたみ/検索機能は無効）
- `dumpHeader` をnullに設定することでヘッダー出力を抑制可能
- Unicode制御文字は `\u{XXXX}` 形式で可視化される

---

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

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

### 推奨読解順序

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

VarDumperのデータモデルを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Data.php | `src/Symfony/Component/VarDumper/Cloner/Data.php` | ダンプ対象のデータ構造。dump(DumperInterface)で走査 |
| 1-2 | Cursor.php | `src/Symfony/Component/VarDumper/Cloner/Cursor.php` | 走査状態を保持。hashKey, hashType, attr等の属性 |
| 1-3 | DumperInterface.php | `src/Symfony/Component/VarDumper/Cloner/DumperInterface.php` | dumpScalar, dumpString, enterHash, leaveHashの各コールバック |

**読解のコツ**: VarDumperはVisitorパターンを採用している。DataがSubject、DumperInterfaceがVisitorに相当する。

#### Step 2: 基底クラスを理解する

HtmlDumperの親クラスであるAbstractDumperとCliDumperを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractDumper.php | `src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php` | 出力先管理、dump()のメインフロー（123-155行目） |
| 2-2 | CliDumper.php | `src/Symfony/Component/VarDumper/Dumper/CliDumper.php` | ANSIカラー装飾、dumpScalar/dumpString/enterHash/leaveHashの実装 |

**主要処理フロー**:
1. **AbstractDumper 123行目**: `dump()` - 出力先設定 → `Data::dump($this)` → `dumpLine(-1)` で終了
2. **CliDumper 126-185行目**: `dumpScalar()` - スカラー値の型判定と装飾
3. **CliDumper 187-274行目**: `dumpString()` - 文字列の分割表示（複数行対応）
4. **CliDumper 276-311行目**: `enterHash()` - オブジェクト/配列の開始出力
5. **CliDumper 313-321行目**: `leaveHash()` - オブジェクト/配列の終了出力

#### Step 3: HtmlDumper固有の処理を理解する

HtmlDumperのオーバーライドメソッドとHTML生成ロジックを読む。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | HtmlDumper.php | `src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php` | テーマ定義（27-62行目）、style()オーバーライド（822-934行目）、getDumpHeader()（142-768行目） |

**主要処理フロー**:
- **79-85行目**: コンストラクタ - dumpId生成、fileLinkFormat設定、デフォルトテーマ設定
- **130-137行目**: `dump()` - extraDisplayOptions設定、親dump()呼出、dumpId再生成
- **142-768行目**: `getDumpHeader()` - JavaScript（展開/折りたたみ/検索）とCSS（テーマスタイル）を含むHTMLヘッダー
- **770-783行目**: `dumpString()` - 画像データのBase64インライン表示対応
- **785-811行目**: `enterHash()` - `<samp>` タグでネスト構造を出力、参照ID付与
- **822-934行目**: `style()` - HTML `<span>` タグによるスタイリング、省略表示、リンク生成
- **936-961行目**: `dumpLine()` - HTMLヘッダー・プレフィックス・サフィックスの付与、数値エンティティ変換

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

```
HtmlDumper::dump(Data, $output, $extraDisplayOptions)
    |
    +-- CliDumper::dump(Data, $output)  [parent]
    |       |
    |       +-- AbstractDumper::dump(Data, $output)  [parent]
    |               |
    |               +-- Data::dump(DumperInterface)
    |                       |
    |                       +-- HtmlDumper::dumpScalar(Cursor, type, value)
    |                       |       +-- CliDumper::dumpKey(Cursor)
    |                       |       +-- HtmlDumper::style(style, value, attr)
    |                       |
    |                       +-- HtmlDumper::dumpString(Cursor, str, bin, cut)
    |                       |       +-- [画像データ時] Base64インライン出力
    |                       |       +-- [通常時] CliDumper::dumpString()
    |                       |
    |                       +-- HtmlDumper::enterHash(Cursor, type, class, hasChild)
    |                       |       +-- CliDumper::enterHash()
    |                       |       +-- <samp> タグ出力
    |                       |
    |                       +-- HtmlDumper::leaveHash(Cursor, type, class, hasChild, cut)
    |                               +-- </samp> タグ出力
    |                               +-- CliDumper::leaveHash()
    |
    +-- HtmlDumper::dumpLine(depth)
            |
            +-- HtmlDumper::getDumpHeader()  [初回のみ]
            +-- mb_encode_numericentity()
            +-- AbstractDumper::dumpLine(depth)
```

### データフロー図

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

PHP変数 -----> VarCloner::cloneVar() -----> Data オブジェクト
                                                |
                                                v
Data -----> HtmlDumper::dump()
                |
                +---> getDumpHeader() -------> CSS + JavaScript
                +---> dumpPrefix ------------> <pre> 開始タグ
                +---> Data::dump(this)
                |       |
                |       +-- dumpScalar() ----> <span> スカラー値
                |       +-- dumpString() ----> <span> 文字列 / <img> 画像
                |       +-- enterHash() -----> <samp> 構造体開始
                |       +-- leaveHash() -----> </samp> 構造体終了
                |
                +---> dumpSuffix ------------> </pre><script> 初期化
                                                      |
                                                      v
                                            HTML出力 ---> ブラウザ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| HtmlDumper.php | `src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php` | ソース | メインクラス（979行） |
| CliDumper.php | `src/Symfony/Component/VarDumper/Dumper/CliDumper.php` | ソース | 親クラス（667行） |
| AbstractDumper.php | `src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php` | ソース | 基底クラス（232行） |
| Data.php | `src/Symfony/Component/VarDumper/Cloner/Data.php` | ソース | ダンプ対象データ構造 |
| Cursor.php | `src/Symfony/Component/VarDumper/Cloner/Cursor.php` | ソース | 走査状態カーソル |
| DumperInterface.php | `src/Symfony/Component/VarDumper/Cloner/DumperInterface.php` | ソース | Dumperインターフェース |
| DataDumperInterface.php | `src/Symfony/Component/VarDumper/Dumper/DataDumperInterface.php` | ソース | DataDumperインターフェース |
| VarCloner.php | `src/Symfony/Component/VarDumper/Cloner/VarCloner.php` | ソース | 変数クローン取得 |
