# 帳票設計書 32-PHP国際化バンドル

## 概要

本ドキュメントは、Symfony IntlコンポーネントにおけるPHP国際化バンドルファイルの出力仕様を定義する帳票設計書である。`PhpBundleWriter`クラスによるICU国際化データのPHP配列形式出力について、処理フロー、データ構造、出力形式を詳細に記載する。

### 本帳票の処理概要

ICU（International Components for Unicode）国際化データをPHP配列形式のファイルとして出力する処理である。通貨、言語、地域、スクリプト、タイムゾーンなどの国際化データを、ロケール単位でPHP配列を返すファイル（`return [...];`形式）として書き出す。

**業務上の目的・背景**：Webアプリケーションの国際化対応において、ICUが提供する国際化データをPHPアプリケーションから最も高速にアクセスできる形式に変換する必要がある。PHP配列形式は`include`/`require`で直接読み込めるため、JSONやXMLのようなパース処理が不要であり、OPCacheによるバイトコードキャッシュの恩恵を受けられるため、本番環境での読み込みパフォーマンスが最も優れている。Symfony Intlコンポーネントのデフォルト読み込み形式として使用される。

**帳票の利用シーン**：Symfony Intlコンポーネントのデータ更新プロセスにおいて、ICUデータソースから最新の国際化データを取得し、PHPアプリケーションが直接利用可能なPHP配列形式に変換する際に利用される。変換されたファイルはSymfonyのソースコードリポジトリにコミットされ、ランタイムで直接参照される。

**主要な出力内容**：
1. ロケール別の通貨データ（通貨コード、通貨名称、通貨記号）をPHP配列として出力
2. ロケール別の言語データ（言語コード、言語名称）をPHP配列として出力
3. ロケール別の地域データ（地域コード、地域名称）をPHP配列として出力
4. ロケール別のスクリプトデータ（スクリプトコード、スクリプト名称）をPHP配列として出力
5. ロケール別のタイムゾーンデータ（タイムゾーンID、表示名称）をPHP配列として出力
6. メタデータ（サポートロケール一覧、エイリアス情報等）をPHP配列として出力

**帳票の出力タイミング**：ICUデータの更新時、またはSymfony Intlコンポーネントのビルドプロセス実行時。`AbstractDataGenerator::generateData()`メソッドの呼び出しに連動して自動実行される。

**帳票の利用者**：Symfonyフレームワークの開発者、Intlコンポーネントのメンテナー、およびICUデータの更新を行うビルドプロセス。出力されたPHPファイルは、全てのSymfony Intlコンポーネントの利用者によってランタイムで間接的に参照される。

## 帳票種別

データエクスポートファイル（国際化リソースバンドル・PHP配列形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIコマンド | N/A | AbstractDataGenerator::generateData()呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PHP |
| 用紙サイズ | N/A（電子ファイル） |
| 向き | N/A |
| ファイル名 | `{locale}.php`（例: `ja.php`, `en.php`, `root.php`, `meta.php`） |
| 出力方法 | ファイルシステムへの直接書き出し |
| 文字コード | UTF-8 |

### PHP固有設定

| 項目 | 内容 |
|-----|------|
| PHPタグ | `<?php`（開始タグのみ、閉じタグなし） |
| 配列エクスポート | `VarExporter::export()`による最適化された配列出力 |
| return文 | `return {配列};`形式でファイル全体がPHP配列を返す |

## 帳票レイアウト

### レイアウト概要

PHPファイルとして、`return`文で配列を返す構造。`VarExporter`によって最適化された読みやすい配列表記が使用される。

```
┌─────────────────────────────────────┐
│  <?php                              │
│                                     │
│  return [                           │
│      'key1' => 'value1',            │
│      'key2' => [                    │
│          'nested_key' => 'value',   │
│      ],                             │
│  ];                                 │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | PHPオープンタグ | `<?php`タグ | 固定テンプレート | テキスト |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ロケールデータキー | 国際化データの識別キー | ICUソースデータ | PHP配列キー（文字列） | N/A |
| 2 | ロケールデータ値 | 国際化データの値（文字列、数値、配列） | ICUソースデータ | PHP配列値 | N/A |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| N/A | N/A | return文で配列を返す構造のためフッター部なし | N/A | N/A |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ロケール | 出力対象のロケール識別子（例: ja, en, fr） | Yes |
| データ種別 | 通貨/言語/地域/スクリプト/タイムゾーン | Yes |
| 出力先パス | PHPファイルの出力ディレクトリパス | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | 配列キー | 元データの順序を保持 |

### 改ページ条件

N/A（電子ファイルのため改ページなし）

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | 本帳票はデータベースを参照しない。ICUバイナリリソースバンドルファイルを入力とする | N/A |

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

#### ICUリソースバンドル（入力データ）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ICUバンドルデータ（配列/Traversable） | PHP配列のreturn値 | ロケール単位で読み込み | `IntlBundleReader`経由で読み込まれたデータ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| N/A | 本帳票に計算項目は存在しない | N/A | データの形式変換のみ実施 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[AbstractDataGenerator::generateData呼び出し] --> B[GeneratorConfig取得]
    B --> C[LocaleScanner::scanLocales実行]
    C --> D[ICUバンドルのコンパイル]
    D --> E{ロケールごとのループ}
    E --> F[generateDataForLocale実行]
    F --> G{データあり?}
    G -->|Yes| H[PhpBundleWriter::write呼び出し]
    G -->|No| E
    H --> I[Traversableをarrayに変換]
    I --> J[再帰的にTraversableを変換]
    J --> K[VarExporter::exportで配列をPHP文字列化]
    K --> L[テンプレートにsprintfで埋め込み]
    L --> M[file_put_contents実行]
    M --> E
    E --> N[rootデータ生成・書き出し]
    N --> O[metaデータ生成・書き出し]
    O --> P[一時ディレクトリ削除]
    P --> Q[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ファイル書き込み失敗 | 出力先ディレクトリへの書き込み権限がない場合 | PHPのfile_put_contentsエラー | 出力先ディレクトリのパーミッションを確認 |
| VarExporter変換失敗 | エクスポート不可能なデータ構造の場合 | VarExporterの例外 | 入力データの妥当性を確認 |
| Traversable変換失敗 | iterator_to_arrayが失敗する場合 | PHP実行時エラー | イテレータの実装を確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 約300ロケール x 5種別 = 約1500ファイル |
| 目標出力時間 | 全ロケール一括で数分以内 |
| 同時出力数上限 | 1（逐次処理） |

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

- 本帳票はICUの公開データを変換するものであり、個人情報は含まれない
- 出力ファイルはアプリケーションのソースコードリポジトリにコミットされ、`require`/`include`で直接実行されるため、出力内容の改ざんは直接的なコード実行につながる
- `VarExporter`は安全なPHPコードのみを生成するよう設計されている
- `@internal`アノテーションにより、外部からの直接利用は非推奨

## 備考

- `PhpBundleWriter`は`@internal`としてマークされており、Symfony内部でのみ利用される
- `VarExporter`コンポーネントを使用してPHP配列をエクスポートするため、`var_export()`と異なり、クロージャやクラスのインスタンスなどの特殊な値も安全にエクスポートできる
- 出力されたPHPファイルはOPCacheによるバイトコードキャッシュの恩恵を受けられるため、JSON形式よりも読み込みが高速
- 対応するリーダークラスとして`PhpBundleReader`が存在する

---

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

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

### 推奨読解順序

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

まず、BundleWriterが受け取るデータ構造とインターフェースを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BundleWriterInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php` | `write(string $path, string $locale, mixed $data): void`メソッドのシグネチャを確認 |
| 1-2 | GeneratorConfig.php | `src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php` | BundleWriterの登録・管理方法を理解。`addBundleWriter()`（行39）で出力先ディレクトリとWriterの対応を保持 |

**読解のコツ**: `BundleWriterInterface`の`mixed $data`パラメータには、実際には配列またはTraversableオブジェクトが渡される。PhpBundleWriterはこれをVarExporterで安全なPHP表現に変換する。

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

処理の起点となる`AbstractDataGenerator`クラスからWriterが呼び出される流れを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php` | `generateData()`メソッド（行36-88）がメインの処理フロー。ロケールスキャン→コンパイル→データ生成→Writer呼び出しの流れ |

**主要処理フロー**:
1. **行42**: `$writers = $config->getBundleWriters()` - 設定からWriter一覧を取得
2. **行46-49**: 出力先ディレクトリの初期化（削除・再作成）
3. **行54**: `$locales = $this->scanLocales(...)` - 対象ロケール一覧のスキャン
4. **行56**: `$this->compileTemporaryBundles(...)` - ICUバンドルの一時コンパイル
5. **行60-68**: ロケールごとのループでデータ生成とWriter呼び出し
6. **行64-65**: `$writer->write($targetDir.'/'.$this->dirName, $locale, $localeData)` - 実際のファイル出力

#### Step 3: PHP出力処理を理解する

`PhpBundleWriter`の具体的な出力処理を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PhpBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/PhpBundleWriter.php` | `write()`メソッド（行25-46）の全処理フロー。テンプレート定義→Traversable変換→VarExporter→ファイル出力 |

**主要処理フロー**:
- **行27-32**: ヒアドキュメントでPHPファイルのテンプレートを定義。`<?php`タグと`return %s;`の構造
- **行34-36**: トップレベルのTraversableオブジェクトを`iterator_to_array`で配列に変換
- **行38-42**: `array_walk_recursive`で入れ子のTraversableも再帰的に配列へ変換
- **行44**: `VarExporter::export($data)`で配列をPHP表現文字列に変換し、`sprintf`でテンプレートに埋め込み、`file_put_contents`でファイル出力

#### Step 4: VarExporterを理解する

配列のPHP文字列化に使用される`VarExporter`の役割を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | VarExporter.php | `src/Symfony/Component/VarExporter/VarExporter.php` | `export()`静的メソッドの仕様。PHP値を安全かつ最適化されたPHPコード文字列に変換する |

**読解のコツ**: `VarExporter`はPHP標準の`var_export()`の改良版であり、より読みやすく、短い配列構文（`[]`）を使用し、クラスインスタンスの復元にも対応する。

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

```
AbstractDataGenerator::generateData()
    |
    +-- GeneratorConfig::getBundleWriters()
    |
    +-- LocaleScanner::scanLocales()
    |
    +-- BundleCompilerInterface::compile()  [一時バンドルコンパイル]
    |
    +-- [ロケールごとのループ]
    |       |
    |       +-- generateDataForLocale()  [抽象メソッド: 各ジェネレーター実装]
    |       |
    |       +-- PhpBundleWriter::write()
    |               |
    |               +-- iterator_to_array()  [Traversable→配列変換]
    |               +-- array_walk_recursive()  [再帰的変換]
    |               +-- VarExporter::export()  [配列→PHP文字列変換]
    |               +-- sprintf()  [テンプレート埋め込み]
    |               +-- file_put_contents()  [ファイル書き出し]
    |
    +-- generateDataForRoot()
    |
    +-- generateDataForMeta()
```

### データフロー図

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

ICUバイナリリソースバンドル ───> IntlBundleReader ───> 配列/Traversable
                                                          |
                                                          v
                                               AbstractDataGenerator
                                             (generateDataForLocale)
                                                          |
                                                          v
                                               PhpBundleWriter::write()
                                                          |
                                              +-----------+-----------+
                                              |                       |
                                     Traversable→配列変換      VarExporter::export
                                              |                       |
                                              v                       v
                                                  sprintf(テンプレート)
                                                          |
                                                          v
                                                   file_put_contents
                                                          |
                                                          v
                                               {locale}.php ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PhpBundleWriter.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/PhpBundleWriter.php` | ソース | PHP配列形式のリソースバンドル書き出し |
| BundleWriterInterface.php | `src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php` | ソース | バンドルライターの共通インターフェース |
| AbstractDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php` | ソース | データ生成の抽象基底クラス（Writerの呼び出し元） |
| GeneratorConfig.php | `src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php` | ソース | Writer登録・ICUバージョン・ソースディレクトリの設定管理 |
| VarExporter.php | `src/Symfony/Component/VarExporter/VarExporter.php` | ソース | PHP配列を安全なPHPコード文字列に変換 |
| CurrencyDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php` | ソース | 通貨データ生成の具体実装 |
| LanguageDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/LanguageDataGenerator.php` | ソース | 言語データ生成の具体実装 |
| RegionDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php` | ソース | 地域データ生成の具体実装 |
| ScriptDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/ScriptDataGenerator.php` | ソース | スクリプトデータ生成の具体実装 |
| TimezoneDataGenerator.php | `src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php` | ソース | タイムゾーンデータ生成の具体実装 |
| PhpBundleReader.php | `src/Symfony/Component/Intl/Data/Bundle/Reader/PhpBundleReader.php` | ソース | PHP配列形式バンドルの読み込み（対応するリーダー） |
