# 機能設計書 19-Process

## 概要

本ドキュメントは、Symfony Processコンポーネントの機能設計を記述する。Processは、サブプロセスでコマンドを実行する機能を提供し、プロセス実行、タイムアウト管理、非同期実行に対応する。

### 本機能の処理概要

**業務上の目的・背景**：アプリケーションから外部コマンドやスクリプトを実行する必要がある場面は多い。PHPのネイティブなproc_*関数は低レベルであり、タイムアウト管理、出力の取得、エラーハンドリング等を個別に実装する必要がある。Processコンポーネントは、これらを高レベルなAPIでラップし、安全で使いやすいプロセス実行機能を提供する。

**機能の利用シーン**：Dotenvコンポーネントでのコマンド展開、Messengerのワーカープロセス管理、デプロイスクリプトの実行、外部ツール（git、npm等）の呼び出しに利用される。

**主要な処理内容**：
1. プロセスの起動と実行（start、run、mustRun）
2. 同期/非同期実行モード
3. タイムアウト管理（timeout、idleTimeout）
4. 標準入出力の管理（stdin、stdout、stderr）
5. 終了コードとプロセス状態の管理
6. シグナル送信（signal）
7. PHP実行可能ファイルの検出（PhpExecutableFinder）
8. PHPサブプロセス実行（PhpProcess、PhpSubprocess）

**関連システム・外部連携**：Dotenvコンポーネント（コマンド展開）、Messengerコンポーネント（ワーカープロセス）、Consoleコンポーネント（ProcessHelper）と連携する。

**権限による制御**：OSレベルのプロセス実行権限に依存する。proc_open等のPHP関数が利用可能であること。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （直接的な関連画面なし） | - | 内部的にプロセス実行の基盤として他機能から利用 |

## 機能種別

プロセス実行 / 外部コマンド呼び出し

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| command | array/string | Yes | 実行するコマンド（配列推奨、文字列はshell経由） | 空でないこと |
| cwd | string/null | No | 作業ディレクトリ（デフォルト: getcwd()） | ディレクトリが存在すること |
| env | array/null | No | 環境変数の配列 | - |
| input | resource/string/Iterator/null | No | 標準入力データ | - |
| timeout | float/null | No | タイムアウト秒数（デフォルト: 60、nullで無制限） | 非負数 |

### 入力データソース

アプリケーションコード、設定ファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| output | string | 標準出力の内容 |
| errorOutput | string | 標準エラー出力の内容 |
| exitCode | int/null | プロセスの終了コード |
| isSuccessful | bool | 終了コードが0かどうか |
| status | string | プロセス状態（ready/started/terminated） |

### 出力先

呼び出し元への返却値

## 処理フロー

### 処理シーケンス

```
1. Processインスタンス生成
   └─ コマンド、作業ディレクトリ、環境変数、入力の設定
2. プロセス起動（start / run）
   └─ proc_open()によるサブプロセス生成
3. パイプ管理
   └─ Unix/Windows環境に応じたパイプ実装の選択
4. 出力読み取り
   └─ stdout/stderrの非ブロッキング読み取り
5. タイムアウトチェック
   └─ 経過時間とtimeout/idleTimeoutの比較
6. 完了待機
   └─ プロセス終了の待機と終了コードの取得
```

### フローチャート

```mermaid
flowchart TD
    A[Process生成] --> B[start/run]
    B --> C[proc_open]
    C --> D{起動成功?}
    D -->|No| E[ProcessStartFailedException]
    D -->|Yes| F[パイプ管理開始]
    F --> G[stdout/stderr読み取り]
    G --> H{タイムアウト?}
    H -->|Yes| I[ProcessTimedOutException]
    H -->|No| J{プロセス終了?}
    J -->|No| G
    J -->|Yes| K[終了コード取得]
    K --> L{mustRun?}
    L -->|Yes| M{exitCode != 0?}
    M -->|Yes| N[ProcessFailedException]
    M -->|No| O[完了]
    L -->|No| O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-19-01 | タイムアウト管理 | timeout（全体タイムアウト）とidleTimeout（出力なしタイムアウト）の2種類 | プロセス実行中 |
| BR-19-02 | mustRun | 終了コードが0以外の場合にProcessFailedExceptionをスロー | mustRun使用時 |
| BR-19-03 | 配列コマンド | 配列形式のコマンドはbypass_shellオプションで直接実行（シェルインジェクション防止） | コンストラクタ |
| BR-19-04 | TTY/PTY | tty（ターミナル直結）またはpty（疑似ターミナル）モードでインタラクティブ実行可能 | setTty/setPty |
| BR-19-05 | IteratorAggregate | プロセス出力をイテレートして非ブロッキングで読み取り可能 | foreach使用時 |

### 計算ロジック

タイムアウト判定: microtime(true)で起動時刻を記録し、現在時刻との差分がtimeout値を超えた場合にタイムアウト。idleTimeoutは最後の出力時刻からの経過時間で判定。

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

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

本コンポーネントはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ProcessStartFailedException | プロセスの起動に失敗 | コマンドの存在と実行権限を確認 |
| - | ProcessTimedOutException | タイムアウト超過 | timeout値の見直しまたはnullで無制限に設定 |
| - | ProcessFailedException | mustRunで終了コード非0 | コマンドとエラー出力を確認 |
| - | ProcessSignaledException | シグナルによるプロセス中断 | シグナルの原因を調査 |
| - | RuntimeException | 実行中のプロセスに対する不正操作 | プロセス状態の確認 |
| - | LogicException | 停止中のプロセスへの操作 | プロセスが実行中であることを確認 |

### リトライ仕様

リトライは呼び出し元で制御する。Process自体にリトライ機能はない。

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

トランザクション管理は行わない。

## パフォーマンス要件

- TIMEOUT_PRECISION（0.2秒）の精度でタイムアウトチェック
- 非ブロッキング出力読み取りにより、大量出力のプロセスでもメモリ使用量を制御
- 出力の無効化（disableOutput）により、出力を読み取らないプロセスのメモリ効率を向上

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

- 配列形式のコマンド使用を推奨（bypass_shell=trueによるシェルインジェクション防止）
- fromShellCommandline()は文字列コマンドをシェル経由で実行するため、ユーザー入力を直接渡さないこと
- ProcessUtils::escapeArgument()による引数のエスケープ

## 備考

- Process::ITER_*定数により、イテレーション時のブロッキング、出力保持、ストリーム選択を制御可能
- PhpExecutableFinderはPHPバイナリのパスを自動検出する
- PhpSubprocessはphp.iniの設定を引き継ぐPHPサブプロセスを起動する
- $exitCodes配列でPOSIXの終了コードの意味を参照可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Process.php（定数・プロパティ） | `src/Symfony/Component/Process/Process.php` | 状態定数（STATUS_READY/STARTED/TERMINATED）、ITER_*定数、内部プロパティ（commandline、timeout、exitcode等） |

**読解のコツ**: Processクラスは状態マシンとして動作する。STATUS_READY（未起動）→STATUS_STARTED（実行中）→STATUS_TERMINATED（終了）の状態遷移を持つ。timeoutとidleTimeoutの2種類のタイムアウトの違いを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Process.php | `src/Symfony/Component/Process/Process.php` | 中核クラス。コンストラクタ、start、run、mustRunの関係 |

**主要処理フロー**:
1. **35-92行目**: クラス定義、定数（ERR/OUT、STATUS_*、ITER_*）、プロパティ定義
2. **99行目**: $exitCodes配列（POSIXの終了コード対応表）
3. コンストラクタ: コマンド、cwd、env、input、timeoutの設定
4. start(): proc_open呼び出し、Pipes生成、callback設定
5. run(): start() + wait() の同期実行ラッパー
6. mustRun(): run() + 終了コードチェック

#### Step 3: パイプ管理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Pipes/ | `src/Symfony/Component/Process/Pipes/` | Unix/Windows環境別のパイプ実装 |

#### Step 4: PHP専用ヘルパー

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PhpExecutableFinder.php | `src/Symfony/Component/Process/PhpExecutableFinder.php` | PHPバイナリの自動検出 |
| 4-2 | PhpProcess.php | `src/Symfony/Component/Process/PhpProcess.php` | PHPスクリプト実行ラッパー |
| 4-3 | PhpSubprocess.php | `src/Symfony/Component/Process/PhpSubprocess.php` | php.ini引き継ぎPHPサブプロセス |

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

```
Process::run() / Process::mustRun()
    │
    ├─ Process::start()
    │      ├─ proc_open()
    │      └─ UnixPipes / WindowsPipes
    │
    ├─ Process::wait()
    │      ├─ updateStatus()
    │      │      └─ proc_get_status()
    │      ├─ readPipes()
    │      │      └─ Pipes::readAndWrite()
    │      └─ checkTimeout()
    │
    └─ mustRun: exitCode チェック
           └─ ProcessFailedException（exitCode != 0）

PhpExecutableFinder::find()
    └─ PHP_BINARY / $_SERVER['_'] / PATH検索
```

### データフロー図

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

コマンド配列         ───▶ Process::start()             ───▶ プロセス起動
                           │
stdin               ───▶ Pipes::write()                ───▶ プロセスのstdin
                           │
                    Process::wait()
                           │
                           ├─ Pipes::readAndWrite()    ───▶ stdout/stderr文字列
                           └─ proc_get_status()        ───▶ exitCode/status
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Process.php | `src/Symfony/Component/Process/Process.php` | ソース | プロセス管理中核クラス |
| PhpProcess.php | `src/Symfony/Component/Process/PhpProcess.php` | ソース | PHPスクリプト実行ラッパー |
| PhpSubprocess.php | `src/Symfony/Component/Process/PhpSubprocess.php` | ソース | PHPサブプロセス |
| PhpExecutableFinder.php | `src/Symfony/Component/Process/PhpExecutableFinder.php` | ソース | PHP実行可能ファイル検出 |
| ExecutableFinder.php | `src/Symfony/Component/Process/ExecutableFinder.php` | ソース | 実行可能ファイル検出 |
| InputStream.php | `src/Symfony/Component/Process/InputStream.php` | ソース | 標準入力ストリーム |
| ProcessUtils.php | `src/Symfony/Component/Process/ProcessUtils.php` | ソース | プロセスユーティリティ |
| Pipes/ | `src/Symfony/Component/Process/Pipes/` | ソース | パイプ管理（Unix/Windows） |
| Exception/ | `src/Symfony/Component/Process/Exception/` | ソース | 例外クラス群 |
| Messenger/ | `src/Symfony/Component/Process/Messenger/` | ソース | Messenger統合 |
