Начало работы
Установка
Установите Greph с помощью Composer:
composer require greph/greph
Так будут установлены библиотека и четыре исполняемых файла в vendor/bin/:
greph: нативный текстовый поиск, поиск по AST и переписывание ASTgreph-index: прогретый текстовый индекс, индекс фактов AST и кэшированный поиск по ASTrg: оболочка совместимости в стиле ripgrepsg: оболочка совместимости в стиле ast-grep
Эти исполняемые файлы работают из vendor/bin/ вашего проекта, поскольку Greph 0.2.3. В более ранних выпусках загрузчик Composer находился только в клоне репозитория Greph, поэтому требуется как минимум эта версия:
composer require greph/greph:^0.2.3
Требования
- PHP 8.2+ для readonly-классов, перечислений, синтаксиса первоклассных вызываемых объектов и продвижения аргументов конструктора
- 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
В выводе используется канонический формат file:line:content, ожидаемый grep, ripgrep и большинством интеграций редакторов.
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 для вывода только путей файлов, -C 2 для двух строк контекста и так далее. Полный список приведен в справочникеCLI.
Первый поиск по AST
Передайте -p и шаблон в формате PHP, чтобы включить структурный поиск:
vendor/bin/greph -p 'new $CLASS()' src
$CLASS — метапеременная, которая захватывает любое имя класса. Шаблон new $CLASS() находит каждое выражение new без аргументов, независимо от класса, форматирования или комментариев. Используйте new $CLASS($$$ARGS), чтобы находить вызовы с любыми аргументами.
Каждое совпадение AST выводится в виде файла, начальной строки и найденного кода:
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.
Первое переписывание
Добавьте -r, чтобы превратить поиск по AST в переписывание:
# 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:
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
Поиск по нескольким прогретым индексам
Можно искать сразу в нескольких прогретых индексах одной командой:
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 учитывает два соглашения о расположении файлов:
.gitignore: учитывается по умолчанию. Передайте--no-ignore, чтобы отключить..grephignore: тот же синтаксис, что у.gitignore, применяется поверх него. Удобно для исключений, специфичных для инструмента, которые не нужно добавлять в систему контроля версий.
По умолчанию каталоги индексов .greph-index, .greph-ast-index и .greph-ast-cache располагаются в выбранном корневом каталоге. Переопределите путь с помощью --index-dir в любой подкоманде greph-index либо используйте .greph-index-set.json для повторяемых конфигураций с несколькими индексами.