Getting Started
Installation
Install Greph via Composer:
composer require greph/grephThis installs the library plus four executables in vendor/bin/:
greph: native text search, AST search, and AST rewritegreph-index: warmed text index, AST fact index, and cached AST searchrg: ripgrep-style compatibility wrappersg: ast-grep-style compatibility wrapper
Requirements
- PHP 8.2+ for readonly classes, enums, first-class callable syntax, and constructor promotion
- ext-json for JSON output and on-disk index payloads
- nikic/php-parser (installed automatically as a Composer dependency)
Optional:
- ext-pcntl for parallel scans. Greph degrades gracefully to single-process execution when it is missing.
- External
rg,grep, andsgbinaries for benchmark comparisons. They are never required at runtime.
Your first text search
Greph's default mode is grep-compatible text search:
vendor/bin/greph -F "function" srcThe output uses the canonical file:line:content format that grep, ripgrep, and most editor integrations expect.
src/Greph.php:31:final class Greph
src/Greph.php:36: public static function walk(string|array $paths, ?WalkOptions $options = null): FileList
src/Text/TextSearcher.php:14:final class TextSearcherAdd -i for case-insensitive matching, -w for whole-word matching, -c for counts, -l for file paths only, -C 2 for two lines of context, and so on. The full list lives in the CLI reference.
Your first AST search
Pass -p and a PHP-shaped pattern to switch to structural search:
vendor/bin/greph -p 'new $CLASS()' src$CLASS is a metavariable that captures any class name. The pattern new $CLASS() matches every constructor call regardless of class, formatting, or comments.
src/Greph.php:38:return (new FileWalker())->walk($paths, $options);
src/Greph.php:49:$searcher = new TextSearcher();
src/Greph.php:50:$codec = new TextResultCodec();Other useful patterns:
# 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)' srcSee Modes / AST Search for the full pattern syntax.
Your first rewrite
Add -r to turn the AST search into a rewrite:
# 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 srcRewrites are format-preserving: only the matched node is replaced, and the surrounding whitespace, indentation, and comments stay intact. See Modes / Rewrite for details.
PHP API
The static Greph\Greph facade exposes the same operations as the CLI:
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";
}The full surface is covered in API.
Indexed search
Repeated workloads benefit from warmed indexes. Build once, then query many times:
# 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)' srcIndexes live in .greph-index, .greph-ast-index, and .greph-ast-cache at the project root by default.
For actively changing trees, choose a lifecycle profile instead of treating every warmed index the same:
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-refreshThe common pattern is:
- keep a stable baseline as
static - keep actively changing overlays as
opportunistic-refresh - inspect stale behavior with
stats --dry-refresh
Multi-index warmed search
You can search several warmed indexes in one command:
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-originNamed index sets
If you do that repeatedly, put the layout into .greph-index-set.json and use the set subcommands instead of repeating flags:
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)' .Planner trace
To see how warmed search is narrowing candidates, add --trace-plan:
vendor/bin/greph-index search --trace-plan -F "function" .
vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' .See Indexed / Text and Indexed / AST for the full warmed workflow.
Compatibility wrappers
If you have tools or agents that already speak ripgrep or ast-grep, drop in the wrappers:
vendor/bin/rg --json -F "function" src
vendor/bin/sg --pattern 'new $CLASS()' src --lang phpBoth wrappers reuse the same engine and are probe-verified against the upstream binaries. The verified surface is documented in Compatibility / rg and Compatibility / sg and reproduced in the generated feature matrix.
Configuration
Greph picks up two on-disk conventions:
.gitignore: respected by default. Pass--no-ignoreto disable..grephignore: same syntax as.gitignore, applied on top. Useful for tool-specific exclusions you do not want in version control.
The default index directories are .greph-index, .greph-ast-index, and .greph-ast-cache at the chosen root. Override with --index-dir on any greph-index subcommand, or use .greph-index-set.json for repeatable multi-index layouts.