
# PHP API

## `Greph\Greph`

`Greph\Greph`クラスは静的なエントリポイントです。検索、書き換え、インデックスの各操作をすべて提供します。どのメソッドも単一パスまたはパスのリストを受け取ります。

```php
use Greph\Greph;
```

### `walk`

```php
public static function walk(string|array $paths, ?WalkOptions $options = null): FileList
```

`$paths`をフラットな`FileList`に解決し、絶対ファイルパスのリストを返します。gitignore、`.grephignore`、ファイルタイプフィルター、globパターン、隠しファイルの対象化、シンボリックリンクの追跡、バイナリ検出、最大ファイルサイズの上限に対応します。

```php
use Greph\Walker\WalkOptions;
use Greph\Walker\FileTypeFilter;

$files = Greph::walk('src', new WalkOptions(
    fileTypeFilter: new FileTypeFilter(['php']),
));

foreach ($files->paths() as $path) {
    echo "$path\n";
}
```

---

### `searchText`

```php
public static function searchText(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
): array
```

テキスト検索を実行し、`list<TextFileResult>`を返します。各`TextFileResult`にはファイルパスと`TextMatch`オブジェクトのリスト（行、列、内容、キャプチャ、省略可能なコンテキスト）が含まれます。

```php
use Greph\Greph;
use Greph\Text\TextSearchOptions;

$results = Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(
        fixedString: true,
        caseInsensitive: true,
        beforeContext: 1,
        afterContext: 1,
        jobs: 4,
    ),
);

foreach ($results as $file) {
    foreach ($file->matches as $match) {
        echo "{$file->file}:{$match->line}:{$match->content}\n";
    }
}
```

`jobs > 1`が有効で、ファイル数がワーカーのしきい値を超えると、`searchText`は自動的にスキャンを`WorkerPool`に割り当てます。それ以外の場合はプロセス内で実行します。

---

### `searchAst`

```php
public static function searchAst(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
): array
```

構造的なAST検索を実行し、`list<AstMatch>`を返します。パターンはPHPソースで記述し、`$VAR`と`$$$VARIADIC`のメタ変数を使います。各`AstMatch`には、ファイル、キャプチャされた`PhpParser\Node`、キャプチャ、開始・終了行とバイトオフセット、一致したソース部分が含まれます。

```php
use Greph\Greph;
use Greph\Ast\AstSearchOptions;

$matches = Greph::searchAst(
    'new $CLASS()',
    'src',
    new AstSearchOptions(),
);

foreach ($matches as $match) {
    echo "{$match->file}:{$match->startLine}:{$match->code}\n";
}
```

---

### `rewriteAst`

```php
public static function rewriteAst(
    string $searchPattern,
    string $rewritePattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
): array
```

構造的な書き換えを実行し、`list<RewriteResult>`を返します。各`RewriteResult`にはファイルパス、元の内容、書き換え後の内容、置換数が含まれます。書式を維持したまま書き換え、該当ノードの範囲だけを置き換えます。ファイルのほかの部分は変更されません。

```php
$rewrites = Greph::rewriteAst(
    'array($$$ITEMS)',
    '[$$$ITEMS]',
    'src',
);

foreach ($rewrites as $result) {
    if ($result->changed()) {
        file_put_contents($result->file, $result->rewrittenContents);
    }
}
```

ファサードはディスクに書き込みません。変更を適用するかどうかは呼び出し側が決めます。CLIは`--dry-run`または`--interactive`が設定されていない限り、変更を適用します。

---

### インデックス付きテキスト検索

#### `buildTextIndex`

```php
public static function buildTextIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): IndexBuildResult
```

`$rootPath`用に、新しいトライグラムと識別子の転置インデックスを構築します。インデックスは`$indexPath`に保存されます（既定値は`$rootPath/.greph-index`）。`$lifecycle`には`static`、`manual-refresh`、`opportunistic-refresh`、`strict-stale-check`を指定できます。ファイル数、トライグラム数、追加・更新・削除・変更なしの件数を含む`IndexBuildResult`を返します。

#### `refreshTextIndex`

```php
public static function refreshTextIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): IndexBuildResult
```

既存のテキストインデックスを差分更新します。ファイルを再ハッシュし、変更されたエントリのみを書き換えます。

#### `searchTextIndexed`

```php
public static function searchTextIndexed(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

ウォームアップ済みのインデックスに対してテキスト検索を実行します。インデックスが存在しない場合はランタイムエラーになります（先に`buildTextIndex`を呼び出してください）。`searchText`と同じ形式の`list<TextFileResult>`を返します。

```php
Greph::buildTextIndex('.');
$results = Greph::searchTextIndexed('function', 'src');
```

#### `searchTextIndexedMany`

```php
public static function searchTextIndexedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?TextSearchOptions $options = null,
): array
```

複数のテキストインデックスディレクトリに対して、ウォームアップ済みのテキスト検索を実行します。Grephは対象となる各インデックスを検索し、絶対ファイルパスで重複を除外します。指定されたどのインデックスルートにも含まれないパスに対してのみ、ネイティブスキャンにフォールバックします。

#### `loadIndexSet`

```php
public static function loadIndexSet(?string $manifestPath = null): IndexSet
```

インデックスセットのマニフェストを読み込みます。既定では現在の作業ディレクトリにある`.greph-index-set.json`を使用します。

#### `searchTextIndexedSet`

```php
public static function searchTextIndexedSet(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

インデックスセットのマニフェストから選択した`text`のエントリを解決し、`searchTextIndexedMany`と同等の処理を実行します。

---

### インデックス付きAST検索

#### `buildAstIndex` / `refreshAstIndex`

```php
public static function buildAstIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstIndexBuildResult
public static function refreshAstIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstIndexBuildResult
```

ASTファクトインデックスを構築するか、差分更新します。抽出したファクトは既定で`$rootPath/.greph-ast-index`に保存されます。

#### `searchAstIndexed`

```php
public static function searchAstIndexed(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

ファクトインデックスを使って候補を絞り込んでから、ソースに対して一致を再検証します。`searchAst`と同じ形式の`list<AstMatch>`を返します。

#### `searchAstIndexedMany`

```php
public static function searchAstIndexedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?AstSearchOptions $options = null,
): array
```

複数のASTインデックスディレクトリに対して、ウォームアップ済みのASTファクト検索を実行します。

#### `searchAstIndexedSet`

```php
public static function searchAstIndexedSet(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

インデックスセットのマニフェストから選択した`ast-index`のエントリを解決し、`searchAstIndexedMany`と同等の処理を実行します。

#### `buildAstCache` / `refreshAstCache`

```php
public static function buildAstCache(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstCacheBuildResult
public static function refreshAstCache(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstCacheBuildResult
```

キャッシュ済みのパースツリーを保存するストアを構築するか、差分更新します。シリアライズしたツリーは既定で`$rootPath/.greph-ast-cache`に保存されます。

#### `searchAstCached`

```php
public static function searchAstCached(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

キャッシュ済みのパースツリーに対してAST検索を実行し、パーサー処理を完全に省略します。`searchAst`と同じ形式の`list<AstMatch>`を返します。

#### `searchAstCachedMany`

```php
public static function searchAstCachedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?AstSearchOptions $options = null,
): array
```

複数のキャッシュディレクトリに対して、ウォームアップ済みのキャッシュAST検索を実行します。

#### `searchAstCachedSet`

```php
public static function searchAstCachedSet(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

インデックスセットのマニフェストから選択した`ast-cache`のエントリを解決し、`searchAstCachedMany`と同等の処理を実行します。

---

## `Greph\Text\TextSearchOptions`

テキスト検索用の読み取り専用オプションオブジェクト。

```php
new TextSearchOptions(
    bool $fixedString = false,
    bool $caseInsensitive = false,
    bool $wholeWord = false,
    bool $invertMatch = false,
    ?int $maxCount = null,
    int $beforeContext = 0,
    int $afterContext = 0,
    bool $countOnly = false,
    bool $filesWithMatches = false,
    bool $filesWithoutMatches = false,
    bool $jsonOutput = false,
    bool $tracePlan = false,
    int $jobs = 1,
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = true,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
    bool $showLineNumbers = true,
    bool $showFileNames = true,
)
```

検証：

- `jobs >= 1`
- `beforeContext, afterContext >= 0`
- `maxCount === null || maxCount >= 1`

ファイルツリーを別途走査する場合は、`walkOptions()`を使って対応する`WalkOptions`を取得してください。

`tracePlan`はウォームアップ済みのインデックス検索で使用されます。また、`greph-index`CLIのフローでは、プランナーの診断情報を`stderr`に出力します。ネイティブの`searchText`自体はこれを使用しません。

---

## `Greph\Ast\AstSearchOptions`

AST検索と書き換え用の読み取り専用オプションオブジェクト。

```php
new AstSearchOptions(
    string $language = 'php',
    int $jobs = 1,
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = true,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
    bool $skipParseErrors = true,
    bool $dryRun = false,
    bool $interactive = false,
    bool $jsonOutput = false,
    bool $tracePlan = false,
)
```

ASTモードの既定のファイルタイプフィルターは`php`です。`skipParseErrors`が`true`（既定値）の場合、パースに失敗したファイルは通知なしでスキップされます。`false`に切り替えると、パースエラーが例外として通知されます。`tracePlan`はウォームアップ済みのAST検索で使用され、`greph-index ast-index|ast-cache search`は候補の絞り込みに関する診断情報を出力します。

---

## `Greph\Walker\WalkOptions`

ファイルウォーカー用の読み取り専用オプションオブジェクト。

```php
new WalkOptions(
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = false,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
)
```

---

## `Greph\Walker\FileTypeFilter`

名前付きのファイルタイプを拡張子リストに解決します。組み込みのエイリアス：

| エイリアス | 拡張子 |
|---|---|
| `css` | `css`、`sass`、`scss` |
| `html` | `htm`、`html`、`phtml` |
| `js` | `cjs`、`js`、`mjs` |
| `json` | `json` |
| `md` | `markdown`、`md` |
| `php` | `inc`、`php`、`php3`、`php4`、`php5`、`php7`、`php8`、`phpt`、`phtml` |
| `txt` | `txt` |
| `ts` | `ts`、`tsx` |
| `xml` | `xml` |
| `yaml` | `yaml`、`yml` |

```php
new FileTypeFilter(includeTypes: ['php'], excludeTypes: ['md']);
```

---

## 結果オブジェクト

### `Greph\Text\TextFileResult`

```php
final readonly class TextFileResult
{
    public string $file;
    /** @var list<TextMatch> */
    public array $matches;

    public function matchCount(): int;
    public function hasMatches(): bool;
}
```

### `Greph\Text\TextMatch`

```php
final readonly class TextMatch
{
    public string $file;
    public int $line;
    public int $column;
    public string $content;
    public string $matchedText;
    /** @var array<int|string, string> */
    public array $captures;
    /** @var list<array{line: int, content: string}> */
    public array $beforeContext;
    /** @var list<array{line: int, content: string}> */
    public array $afterContext;
}
```

### `Greph\Ast\AstMatch`

```php
final readonly class AstMatch
{
    public string $file;
    public PhpParser\Node $node;
    /** @var array<string, mixed> */
    public array $captures;
    public int $startLine;
    public int $endLine;
    public int $startFilePos;
    public int $endFilePos;
    public string $code;
}
```

### `Greph\Ast\RewriteResult`

```php
final readonly class RewriteResult
{
    public string $file;
    public string $originalContents;
    public string $rewrittenContents;
    public int $replacementCount;

    public function changed(): bool;
}
```

### `Greph\Index\IndexBuildResult`

```php
final readonly class IndexBuildResult
{
    public string $rootPath;
    public string $indexPath;
    public int $fileCount;
    public int $trigramCount;
    public int $addedFiles;
    public int $updatedFiles;
    public int $deletedFiles;
    public int $unchangedFiles;
}
```

`AstIndexBuildResult`と`AstCacheBuildResult`は、`factCount`と`cachedTreeCount`をそれぞれ置き換えた同じ形式です。

---

## 例外

Grephは、すべて`Greph\Exceptions`に属する、型付き例外を3種類スローします。

| 例外 | 発生する条件 |
|---|---|
| `WalkerException` | トラバーサル中のファイルシステムエラー（パスが存在しない、ディレクトリを読み取れない） |
| `PatternException` | 無効な正規表現またはASTパターン |
| `ParseException` | PHPのソースを解析できない（`skipParseErrors: false`の場合のみ） |

インデックスを使う検索メソッドは、指定された場所にインデックスがない場合に`\RuntimeException`を発生させます。`greph-index` CLIには、この例外を捕捉して代わりにインデックスを使わないスキャンにフォールバックする`--fallback scan`オプションがあります。
