# 機能設計書 24-starts_with_ci

## 概要

本ドキュメントは、Hack Standard Library（HSL）の `Str\starts_with_ci` 関数の機能設計書です。文字列が指定されたプレフィックス（接頭辞）で始まるかどうかを、大文字小文字を無視して判定する機能を提供します。

### 本機能の処理概要

`Str\starts_with_ci` 関数は、与えられた文字列が特定のプレフィックスで始まるかどうかを、大文字小文字を区別せずに判定してブール値で返す関数です。「ci」は「case-insensitive」の略です。

**業務上の目的・背景**：文字列の先頭判定において、大文字小文字を区別しない比較が必要な場面は多く存在します。例えば、URLスキームの判定（`HTTP://`と`http://`を同一視）、コマンドライン引数の解析（大文字小文字を区別しないオプション）、設定ファイルの解析などがあります。この関数は、そのような大文字小文字を無視した先頭判定を簡潔に実現します。

**機能の利用シーン**：
- URLスキームの判定で大文字小文字を区別しない場合（例：`HTTP://`、`http://`、`Http://` を同一視）
- ファイルパスの検証（Windowsなど大文字小文字を区別しないファイルシステム）
- コマンドライン引数の解析（例：`--help`、`--HELP`、`--Help` を同一視）
- 設定ファイルのキー判定

**主要な処理内容**：
1. 入力文字列 `$string` とプレフィックス `$prefix` を受け取る
2. 内部実装関数 `_Str\starts_with_ci_l` に処理を委譲
3. プレフィックスが空文字列の場合は常に `true` を返す
4. 文字列の先頭をプレフィックスと大文字小文字を無視して比較
5. 一致する場合は `true`、しない場合は `false` を返す

**関連システム・外部連携**：外部システムとの連携はありません。純粋な文字列操作関数です。

**権限による制御**：特に権限による制御はありません。純粋関数（Pure function）として実装されており、副作用はありません。

## 関連画面

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

## 機能種別

バリデーション / 文字列判定処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $string | string | Yes | 検査対象の文字列 | なし（空文字列も許可） |
| $prefix | string | Yes | 検索するプレフィックス（接頭辞） | なし（空文字列も許可） |

### 入力データソース

関数呼び出し時の引数として直接渡される文字列データ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | bool | 文字列がプレフィックスで始まる場合（大文字小文字無視）は `true`、そうでない場合は `false` |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 関数呼び出し
   └─ $string と $prefix を引数として受け取る
2. 内部実装への委譲
   └─ _Str\starts_with_ci_l($string, $prefix) を呼び出し
3. 大文字小文字を無視した比較
   └─ 内部で文字列を正規化して比較
4. 結果の返却
   └─ bool 値を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始: starts_with_ci呼び出し] --> B{プレフィックスは空文字列?}
    B -->|Yes| C[true を返す]
    B -->|No| D{文字列長 >= プレフィックス長?}
    D -->|No| E[false を返す]
    D -->|Yes| F[文字列の先頭とプレフィックスを大文字小文字無視で比較]
    F --> G{一致する?}
    G -->|Yes| C
    G -->|No| E
    C --> H[終了]
    E --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 空プレフィックス | プレフィックスが空文字列の場合、常にtrueを返す | $prefix === '' |
| BR-02 | 大文字小文字無視 | 比較は大文字小文字を区別しない（A-Z と a-z は同一視） | 常時 |
| BR-03 | バイト単位比較 | ASCII範囲の大文字小文字変換後、バイト単位で比較 | 常時 |

### 計算ロジック

文字列の先頭 `length($prefix)` バイトを大文字小文字を無視して `$prefix` と比較。

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

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

本機能はデータベース操作を行いません。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本関数は例外をスローしない | - |

### リトライ仕様

該当なし。

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

該当なし（データベース操作なし）。

## パフォーマンス要件

- 計算量: O(n) ここで n はプレフィックスの長さ
- 大文字小文字変換のオーバーヘッドあり
- 純粋関数として実装されており、キャッシュや状態を持たない
- コンテキスト係数 `[]:` が指定されており、副作用なしで実行可能

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

- 純粋関数のため、セキュリティ上の懸念は最小限
- パス検証に使用する場合は、正規化されたパスを使用すること
- ロケールによる大文字小文字変換の違いに注意（例：トルコ語の i/I 問題）

## 備考

- 大文字小文字を区別した比較が必要な場合は `Str\starts_with()` を使用すること
- ロケールを考慮した大文字小文字無視比較が必要な場合は `Str\starts_with_ci_l()` を使用すること

---

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

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

### 推奨読解順序

#### Step 1: 公開APIを理解する

まず、外部から呼び出される公開関数のインターフェースを理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | introspect.php | `src/str/introspect.php` | 公開関数 `starts_with_ci` の定義とドキュメントコメント |

**主要処理フロー**:
- **274-280行目**: 関数のドキュメントコメント。case-insensitive版であることの説明と関連関数への参照
- **281-286行目**: 関数シグネチャ。`string $string` と `string $prefix` を引数に取り、`bool` を返す
- **285行目**: 内部実装 `_Str\starts_with_ci_l` への委譲

**読解のコツ**: `_ci` サフィックスは「case-insensitive」を意味し、大文字小文字を無視した比較を行うことを示します。

#### Step 2: 内部実装を理解する

ロケール対応版の実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | introspect_l.php | `src/str/introspect_l.php` | ロケール対応版の実装詳細 |

**主要処理フロー**:
- **295-312行目**: ロケール対応版 `starts_with_ci_l` の定義
- **311行目**: `_Str\starts_with_ci_l($string, $prefix, $locale)` への委譲

#### Step 3: テストケースを理解する

テストコードから具体的な動作仕様を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StrIntrospectTest.php | `tests/str/StrIntrospectTest.php` | テストケースから具体的な入出力パターンを理解 |

**主要処理フロー**:
- **390-422行目**: `provideStartsWithCI` メソッドでテストデータを定義
- **391-395行目**: 空文字列同士の比較は `true`
- **396-400行目**: プレフィックスが空文字列の場合は `true`
- **401-405行目**: 正常な接頭辞一致は `true`
- **406-410行目**: 文字列よりプレフィックスが長い場合は `false`
- **417-421行目**: 大文字小文字が異なっても `true`（"hello world" と "HELLO"）
- **425-432行目**: テスト実行メソッド

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

```
Str\starts_with_ci($string, $prefix)
    │
    └─ _Str\starts_with_ci_l($string, $prefix)
           │
           └─ [HHVM内部実装]
                  └─ 大文字小文字無視の先頭比較
```

### データフロー図

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

$string (string) ───┬──▶ starts_with_ci() ───▶ bool (true/false)
                    │         │
$prefix (string) ───┘         │
                              ▼
                    _Str\starts_with_ci_l()
                              │
                              ▼
                    [大文字小文字正規化]
                              │
                              ▼
                    [先頭比較処理]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| introspect.php | `src/str/introspect.php` | ソース | 公開API定義 |
| introspect_l.php | `src/str/introspect_l.php` | ソース | ロケール対応実装 |
| StrIntrospectTest.php | `tests/str/StrIntrospectTest.php` | テスト | ユニットテスト |
