コンテンツへスキップ

はじめに

インストール

ComposerでGrephをインストールします。

シェル
composer require greph/greph

これにより、ライブラリと4つの実行ファイルがvendor/bin/にインストールされます。

  • greph: ネイティブのテキスト検索、AST検索、AST書き換え
  • greph-index: ウォーム済みテキストインデックス、ASTファクトインデックス、キャッシュ済みAST検索
  • rg: ripgrep形式の互換ラッパー
  • sg: ast-grep形式の互換ラッパー

Greph 0.2.3以降では、これらの実行ファイルをプロジェクトのvendor/bin/から使えます。それ以前のリリースでは、ComposerのオートローダーをGrephリポジトリのクローン内でしか見つけられなかったため、少なくともこのバージョンが必要です。

シェル
composer require greph/greph:^0.2.3

必要条件

  • PHP 8.2+ readonlyクラス、enum、first-class callable構文、コンストラクター昇格に対応
  • ext-json は JSON 出力とディスク上のインデックスペイロードに使用
  • ext-ctype はパターンとオプションの解析に使用
  • ext-tokenizer は PHP-Parser と AST の事前フィルターに使用
  • ext-zlib はキャッシュ済み AST ストア(greph-index ast-cache)に使用
  • nikic/php-parser(Composer の依存関係として自動インストール)

ext-json、ext-ctype、ext-tokenizerは、ほぼすべてのPHPビルドで有効になっています。現時点でcomposer.jsonが宣言しているのはext-jsonのみ(#5)のため、ほかの拡張が欠けていても Composer は警告しません。

任意:

  • 並列スキャンには ext-pcntl を使用します。Grephは、これがない場合も単一プロセスで動作します。
  • ベンチマーク比較用の外部rg、grep、sgバイナリ。実行時には必要ありません。

検索、書き換え、インデックス作成ではproc_open()もshell_exec()も呼び出されません。分岐するのは並列スキャンのみで、pcntl_fork()がない場合は単一プロセスにフォールバックします。proc_open()、shell_exec()、またはpcntl_fork()を無効にするホストについては、プロセス制限のあるホストをご覧ください。

Grephのデフォルトモードは grep 互換のテキスト検索です:

シェル
vendor/bin/greph -F "function" src

出力には、grep、ripgrep、およびほとんどのエディター連携が想定する標準file:line:content形式を使用します。

Text
src/Greph.php:41:    public static function walk(string|array $paths, ?WalkOptions $options = null): FileList
src/Greph.php:50:    public static function searchText(string $pattern, string|array $paths, ?TextSearchOptions $options = null): array
src/Greph.php:81:    public static function buildTextIndex(

大文字と小文字を区別しない検索には-i、単語全体の一致には-w、件数の表示には-c、ファイルパスのみの表示には-l、前後2行の表示には-C 2などを追加します。全オプションはCLIリファレンスに記載されています。

構造検索に切り替えるには、-pとPHP形式のパターンを渡します:

シェル
vendor/bin/greph -p 'new $CLASS()' src

$CLASSは、任意のクラス名を捕捉するメタ変数です。パターンnew $CLASS()は、クラスや書式、コメントにかかわらず、引数のないすべてのnew式に一致します。任意の引数を持つ呼び出しにはnew $CLASS($$$ARGS)を使います。

各 AST の一致結果は、ファイル名、開始行、該当するコードの順に出力されます:

Text
src/Greph.php:43:new FileWalker()
src/Greph.php:52:new TextSearchOptions()
src/Greph.php:54:new TextSearcher()

その他の便利なパターン:

シェル
# Any method call with any arguments
vendor/bin/greph -p '$obj->$method($$$ARGS)' src

# Any function declaration with a void return type
vendor/bin/greph -p 'function $name($$$PARAMS): void {}' src

# Old-style array calls
vendor/bin/greph -p 'array($$$ITEMS)' src

パターン構文の詳細はモード / AST検索を参照してください。

書き換えを始める

AST検索を使った書き換えを行うには、-rを追加します:

シェル
# Preview only
vendor/bin/greph -p 'array($$$ITEMS)' -r '[$$$ITEMS]' --dry-run src

# Apply
vendor/bin/greph -p 'array($$$ITEMS)' -r '[$$$ITEMS]' src

# Confirm each file before writing
vendor/bin/greph -p 'array($$$ITEMS)' -r '[$$$ITEMS]' --interactive src

書き換えでは、一致部分以外の書式が保たれます。置き換えられるのは一致したノードのみで、周囲の空白、インデント、コメントはそのまま残ります。一致したノード自体はテンプレートから新たに出力されるため、そのレイアウトは整えられ、内部のコメントは失われる場合があります。詳しくはモード / 書き換えを参照してください。

PHP API

静的なGreph\Grephファサードでは、CLIと同じ操作を利用できます:

PHP
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Text\TextSearchOptions;

$results = Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(fixedString: true, caseInsensitive: true),
);

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

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

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

すべての機能はAPIで網羅しています。

同じ処理を繰り返す場合は、インデックスを事前に作成しておくと便利です。一度作成すれば、何度でも検索できます:

シェル
# Text index
vendor/bin/greph-index build .
vendor/bin/greph-index search -F "function" .

# AST fact index
vendor/bin/greph-index ast-index build .
vendor/bin/greph-index ast-index search 'new $CLASS()' src

# Cached parsed-tree index
vendor/bin/greph-index ast-cache build .
vendor/bin/greph-index ast-cache search 'array($$$ITEMS)' src

デフォルトでは、プロジェクトルートの.greph-index、.greph-ast-index、.greph-ast-cacheにインデックスが保存されます。

頻繁に変更されるツリーでは、事前作成したインデックスを一律に扱わず、ライフサイクルプロファイルを選択してください:

シェル
vendor/bin/greph-index build . --lifecycle static
vendor/bin/greph-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
vendor/bin/greph-index stats . --dry-refresh

一般的な構成は次のとおりです:

  • 安定したベースラインにはstaticを使用
  • 頻繁に変わるオーバーレイにはopportunistic-refreshを使用
  • 古くなった場合の動作確認にはstats --dry-refreshを使用

1つのコマンドで、複数の事前作成済みインデックスを検索できます:

シェル
vendor/bin/greph-index search -F "apply_filters" . \
  --index-dir wordpress/.greph-index \
  --index-dir wp-content/plugins/my-plugin/.greph-index \
  --show-index-origin

vendor/bin/greph-index ast-index search 'new $CLASS()' . \
  --index-dir wordpress/.greph-ast-index \
  --index-dir wp-content/plugins/my-plugin/.greph-ast-index \
  --show-index-origin

名前付きインデックスセット

この操作を繰り返す場合は、構成を.greph-index-set.jsonに記述し、フラグを毎回指定する代わりにセット用サブコマンドを使います:

シェル
vendor/bin/greph-index set build
vendor/bin/greph-index set stats --dry-refresh
vendor/bin/greph-index set search --show-index-origin -F "apply_filters" .
vendor/bin/greph-index set search --mode ast-index 'new $CLASS()' .
vendor/bin/greph-index set search --mode ast-cache 'array($$$ITEMS)' .

プランナーのトレース

事前作成済みインデックス検索で候補がどのように絞り込まれるか確認するには、--trace-planを追加します:

シェル
vendor/bin/greph-index search --trace-plan -F "function" .
vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' .

事前作成済みインデックスを使った検索の詳細は、インデックス / テキストとインデックス / ASTを参照してください。

互換ラッパー

ripgrep または ast-grep を使うツールやエージェントには、ラッパーをそのまま導入できます:

シェル
vendor/bin/rg --json -F "function" src
vendor/bin/sg --pattern 'new $CLASS()' src --lang php

どちらのラッパーも同じエンジンを使用し、上流のバイナリとのプローブ検証済みです。検証済みの機能は互換性 / rgと互換性 / sgに記載され、生成された機能マトリクスにも掲載されています。

設定

Grephは、ディスク上にある2つの規則を適用します:

  • .gitignore: デフォルトで適用されます。無効にするには--no-ignoreを渡します。
  • .grephignore: .gitignoreと同じ構文で、その上に適用されます。バージョン管理に含めたくない、ツール固有の除外設定に便利です。

デフォルトのインデックスディレクトリは、選択したルートの.greph-index、.greph-ast-index、.greph-ast-cacheです。任意のgreph-indexサブコマンドで--index-dirを使って変更するか、繰り返し使える複数インデックス構成には.greph-index-set.jsonを使用してください。