# 機能設計書 87-select_keys

## 概要

本ドキュメントは、Hack Standard Library (HSL) の Dict モジュールにおける `select_keys` 関数の機能設計を記述する。この関数は、入力コンテナと指定されたキーの Traversable の両方に存在するキーのエントリのみを含む新しい dict を返す機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：データ処理において、特定のキーセットに対応するエントリのみを抽出したいケースは多い。例えば、ユーザーが選択した項目のみを表示する、設定ファイルから必要なキーのみを読み込む、API レスポンスから必要なフィールドのみを抽出するなどである。本関数は、キーのリストを指定して効率的に部分集合を取得するためのユーティリティを提供する。

**機能の利用シーン**：
- 許可されたキーのセットに基づいてデータをフィルタリングする場合
- ユーザーが選択した項目のみを取得する場合
- 設定やパラメータの一部のみを抽出する場合
- ホワイトリスト方式でデータをフィルタリングする場合

**主要な処理内容**：
1. 結果用の空 dict を初期化
2. 入力コンテナが空でないことを確認
3. 指定されたキーの Traversable を順次イテレート
4. 各キーが入力コンテナに存在する場合、結果の dict に追加
5. 結果の dict を返却（キーの順序は $keys の Traversable の順序に従う）

**関連システム・外部連携**：本関数は純粋な計算処理であり、外部システムとの連携はない。

**権限による制御**：本関数は汎用ユーティリティであり、権限による制御は行わない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはUIを持たないライブラリのため画面なし |

## 機能種別

計算処理（選択・抽出）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $container | KeyedContainer<Tk, Tv> | Yes | 抽出元のコンテナ | なし |
| $keys | Traversable<Tk> | Yes | 抽出するキーのリスト | なし |

### 入力データソース

関数引数として直接渡される KeyedContainer オブジェクトとキーの Traversable。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | dict<Tk, Tv> | 指定されたキーに対応するエントリのみを含む dict（$keys の順序に従う） |

### 出力先

関数の戻り値として呼び出し元に返却。

## 処理フロー

### 処理シーケンス

```
1. 結果用の空 dict を初期化
2. 入力コンテナが空かどうかを確認
   └─ 空の場合、以降の処理をスキップして空の dict を返却
3. $keys を foreach でイテレート
   ├─ 各キーが $container に存在するか確認（C\contains_key）
   └─ 存在する場合、結果 dict にエントリを追加
4. 結果の dict を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[result = dict[]]
    B --> C{container は空か?}
    C -->|Yes| D[result を返却]
    C -->|No| E{次のキーがあるか?}
    E -->|No| D
    E -->|Yes| F{キーは container に存在するか?}
    F -->|Yes| G[result にエントリを追加]
    F -->|No| E
    G --> E
    D --> H[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-01 | キーの存在確認 | $container に存在するキーのみが結果に含まれる | 常時 |
| BR-87-02 | $keys の順序優先 | 結果の dict は $keys の順序に従う（$container の順序ではない） | 常時 |
| BR-87-03 | 重複キーの処理 | $keys に重複キーがある場合、最後の出現位置が優先される | 常時 |
| BR-87-04 | 存在しないキーの無視 | $keys に $container に存在しないキーが含まれていても無視される | 常時 |

### 計算ロジック

選択処理:
- 結果 = { (k, $container[k]) | k in $keys AND C\contains_key($container, k) }
- 結果の順序は $keys のイテレート順に従う

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

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

本関数はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | 不正な型の引数が渡された場合 | Hack型システムによりコンパイル時に検出 |

### リトライ仕様

本関数は純粋関数であり、リトライの概念は適用されない。

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

本関数はステートレスな純粋関数であり、トランザクション管理は不要。

## パフォーマンス要件

- 時間計算量: O(k)、k は $keys のサイズ（C\contains_key は O(1)）
- 空間計算量: O(k)、k は $keys のサイズ

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

- 純粋関数であり、副作用がないためセキュリティリスクは低い
- ホワイトリスト方式のフィルタリングに使用可能（許可されたキーのみを選択）

## 備考

- 述語関数でキーをフィルタリングする場合は `Dict\filter_keys()` を使用すること
- $container ではなく $keys の順序が結果に反映されることに注意
- KeyedContainer を使用するため、イテレータは直接渡せない（まず dict に変換する必要がある）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/dict/select.php` | select_keys 関数のシグネチャと型パラメータ |
| 1-2 | introspect.php | `src/c/introspect.php` | contains_key と is_empty 関数の実装 |

**読解のコツ**: `KeyedContainer<Tk, Tv>` は dict, Map, Vector などのインデックスアクセス可能なコンテナ。`Traversable<Tk>` はキーのイテラブル。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.php | `src/dict/select.php` | select_keys 関数の実装（165-178行目） |

**主要処理フロー**:
1. **165-168行目**: 関数シグネチャの定義
2. **169行目**: 結果 dict の初期化
3. **170行目**: コンテナが空でないことを確認（C\is_empty の否定）
4. **171-175行目**: foreach ループでキーを処理
5. **176-177行目**: 結果を返却

#### Step 3: 依存関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | introspect.php | `src/c/introspect.php` | contains_key（72-81行目）- O(1) のキー存在確認 |
| 3-2 | introspect.php | `src/c/introspect.php` | is_empty（124-131行目）- コンテナの空判定 |

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

```
Dict\select_keys($container, $keys)
    |
    +-- C\is_empty($container)  [空判定による早期リターン最適化]
    |
    +-- foreach ($keys as $key)
            |
            +-- C\contains_key($container, $key)  [O(1) キー存在確認]
            |       |
            |       +-- \array_key_exists($key, $container)
            |
            +-- $result[$key] = $container[$key]  [条件付きで追加]
```

### データフロー図

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

$container ─────────────> キー存在確認 ──────────────────> dict<Tk, Tv>
(KeyedContainer<Tk, Tv>)    |                              ($keys の順序)
                            |
$keys ──────────────────> foreach ループ
(Traversable<Tk>)           |
                            +-- キーが存在: 結果に追加
                            +-- キーが不存在: スキップ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/dict/select.php` | ソース | select_keys 関数の実装 |
| introspect.php | `src/c/introspect.php` | ソース | contains_key, is_empty 関数の実装 |
| DictSelectTest.php | `tests/dict/DictSelectTest.php` | テスト | select_keys のユニットテスト（336-374行目） |
