# 機能設計書 20-contains_ci

## 概要

本ドキュメントは、Hack Standard Library（HSL）のStr名前空間における`contains_ci`関数の機能設計を記述する。この関数は、文字列内に指定した部分文字列が含まれるかどうかを大文字小文字を無視して判定する。

### 本機能の処理概要

`contains_ci`関数は、"haystack"文字列内に"needle"文字列が含まれているかを判定し、真偽値を返す。大文字と小文字を区別しない（case-insensitive）検索を行い、オプションでオフセット位置を指定できる。

**業務上の目的・背景**：ユーザー入力の検索、ファイル名・拡張子の判定、HTMLタグやHTTPヘッダーの検出など、大文字小文字を区別せずに部分文字列の存在を確認したい場面は多い。この関数により、明示的な大文字/小文字変換なしに効率的な検索が可能になる。

**機能の利用シーン**：ユーザー検索クエリのマッチング、ファイル拡張子の判定、HTTPヘッダーの検出、HTMLタグの検索、コマンドライン引数の解析、設定値の検索など、大文字小文字を区別しない文字列検索が必要な場面で使用される。

**主要な処理内容**：
1. haystack文字列とneedle文字列を受け取る
2. needleが空文字列の場合はオフセット検証後にtrueを返す
3. search_ci関数を呼び出して位置を検索（大文字小文字無視）
4. 検索結果がnullでなければtrueを返す

**関連システム・外部連携**：内部で`Str\search_ci`関数を使用する。

**権限による制御**：特段の権限制御はない。純粋関数として動作する。

## 関連画面

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

## 機能種別

文字列検索 / 純粋関数

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| haystack | string | Yes | 検索対象の文字列 | - |
| needle | string | Yes | 検索する部分文字列 | - |
| offset | int | No | 検索開始位置（デフォルト: 0） | 範囲外の場合InvalidArgumentException |

### 入力データソース

関数の引数として渡される文字列

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | needleがhaystackに含まれる場合true、含まれない場合false（大文字小文字無視） |

### 出力先

呼び出し元に真偽値を返す

## 処理フロー

### 処理シーケンス

```
1. 引数を受け取る
   ├─ haystack: 検索対象文字列
   ├─ needle: 検索文字列
   └─ offset: 開始位置（デフォルト0）
2. needleが空文字列の場合
   ├─ offset=0ならtrueを返す
   └─ offsetが範囲外ならInvalidArgumentException
3. search_ci関数を呼び出し
   └─ needleの位置を大文字小文字無視で検索
4. 結果を返す
   ├─ 検索結果がnullでなければtrue
   └─ nullの場合はfalse
```

### フローチャート

```mermaid
flowchart TD
    A[contains_ci呼び出し] --> B{needleが空?}
    B -->|Yes| C{offset == 0?}
    C -->|Yes| D[true返却]
    C -->|No| E{offsetが範囲内?}
    E -->|Yes| D
    E -->|No| F[InvalidArgumentException]
    B -->|No| G[search_ci実行]
    G --> H{結果がnull?}
    H -->|No| I[true返却]
    H -->|Yes| J[false返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 大文字小文字無視 | 大文字と小文字を同一視して検索する | 常時適用 |
| BR-02 | 空文字列検索 | 空文字列は常に含まれると判定（オフセット検証後） | needle === '' |
| BR-03 | 負のオフセット | 負のオフセットは末尾からの位置を示す | offset < 0 |
| BR-04 | 純粋関数 | 副作用なし、同じ入力には同じ出力 | 常時適用 |

### 計算ロジック

```
contains_ci(haystack, needle, offset) = search_ci(haystack, needle, offset) !== null
```

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

該当なし（本機能は純粋な文字列操作でデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidArgumentException | オフセットが文字列長の範囲外 | オフセット値を確認 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 計算量: O(n * m) （n: haystack長、m: needle長）
- メモリ: 追加のメモリ割り当てなし

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

- 特段のセキュリティリスクはない
- ユーザー入力を直接検索に使用する場合は適切なサニタイズを検討

## 備考

- 位置を取得したい場合は`Str\search_ci()`を使用
- 大文字小文字を区別した検索には`Str\contains()`を使用
- 関連ガイド: /hack/built-in-types/string

---

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

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

### 推奨読解順序

#### Step 1: 関数定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | introspect.php | `src/str/introspect.php` | contains_ci関数の定義と実装 |

**読解のコツ**: `_ci`サフィックスは「case-insensitive」（大文字小文字無視）を意味する。contains関数との違いは内部で呼び出す関数がsearch_ciである点。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | introspect.php | `src/str/introspect.php` | contains_ci関数の実装詳細 |

**主要処理フロー**:
1. **78-91行目**: docコメント。オフセット、関連関数への参照
2. **92-110行目**: contains_ci関数本体
3. **92-96行目**: 関数シグネチャ
4. **97-108行目**: 空文字列の特別処理とオフセット検証
5. **109行目**: search_ci関数の呼び出しと結果判定

#### Step 3: 関連関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | introspect.php | `src/str/introspect.php` | search_ci関数の実装 |
| 3-2 | introspect.php | `src/str/introspect.php` | contains関数との比較 |

**主要処理フロー**:
- **search_ci関数（219-229行目）**: 内部でstripos_lを呼び出して大文字小文字無視で位置を検索
- **contains関数との違い**: searchの代わりにsearch_ciを呼び出す

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

```
Str\contains_ci(haystack, needle, offset)
    │
    ├─ needle === '' の場合
    │      └─ オフセット検証 → true/例外
    │
    └─ Str\search_ci(haystack, needle, offset)
           │
           └─ _Str\stripos_l(haystack, needle, offset)
                  │
                  └─ 位置または負の値を返却（大文字小文字無視）
```

### データフロー図

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

haystack ────────────┐
                     │
needle ──────────────┼──▶ Str\contains_ci() ──────────▶ bool
                     │         │
offset (opt) ────────┘         ▼
                         ┌─────────────┐
                         │ 空文字列判定 │
                         └──────┬──────┘
                                │
                         ┌──────▼──────┐
                         │ Str\search_ci│
                         │(大文字小文字無視)│
                         └──────┬──────┘
                                │
                         ┌──────▼──────┐
                         │ null判定    │
                         └─────────────┘
                                │
                         ┌──────┴──────┐
                         ▼             ▼
                       true         false
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| introspect.php | `src/str/introspect.php` | ソース | contains_ci関数およびsearch_ci関数の実装 |
| introspect_l.php | `src/str/introspect_l.php` | ソース | ロケール対応版の関数 |
