
# AST-keresés

A Greph AST-módja PHP forrást keres a szerkezete, nem a szövege alapján. A minták hétköznapi PHP kódban íródnak, `$VARIABLE` és `$$$VARIADIC` metaváltozókkal. A mintát a [nikic/php-parser](https://github.com/nikic/PHP-Parser) elemzi a keresett forrással azonos AST-struktúrára, majd csomópontról csomópontra illeszti.

Ugyanez a modell, mint a [ast-grep](https://ast-grep.github.io/) esetében, a `sg` kompatibilitási burkoló pedig ugyanennek a motornak a tetején teszi elérhetővé a ast-grep CLI felületét.

## Gyors példák

```bash
# Find every constructor call
./vendor/bin/greph -p 'new $CLASS()' src

# Find every method call with any number of arguments
./vendor/bin/greph -p '$obj->$method($$$ARGS)' src

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

# Find void-returning functions
./vendor/bin/greph -p 'function $name($$$PARAMS): void {}' src

# Find isset ternaries that should be ??
./vendor/bin/greph -p 'isset($x) ? $x : $default' src
```

## Mintaszintaxis

A minta érvényes PHP forráskód. Bárhol, ahová valódi kifejezés vagy utasítás kerülhet, metaváltozót helyettesíthet be az adott csomópont rögzítéséhez.

| Szintaxis | Illesztés | Példa |
|---|---|---|
| `$VAR` | Bármely egy AST-csomópont, rögzítése `VAR` néven | A `$x + $y` illeszkedik erre: `foo() + bar` |
| `$_` | Bármely egy AST-csomópont, rögzítés nélkül | A `$_->method()` bármely fogadó objektumra illeszkedik |
| `$$$ARGS` | Nulla vagy több csomópont (változó hosszúságú), rögzítése `ARGS` néven | A `func($$$ARGS)` illeszkedik ezekre: `func()`, `func(1)`, `func(1, 2, 3)` |
| `$VAR` (ismételve) | Ugyanannak a `$VAR`-nek mindkét helyen azonos szerkezetűnek kell lennie | A `$x == $x` illeszkedik erre: `a == a`, de erre nem: `a == b` |

A metaváltozó neve konvenció szerint nagybetűs, de nem kötelező annak lennie. A `$_` nem rögzítő helyettesítő karakter.

A `$$$VARIADIC` mindenhol használható, ahol a PHP csomópontok listáját engedi: függvényargumentumoknál, tömbelemeknél, paraméterlistáknál és utasítástörzsekben. A rögzítés a teljes illesztett sorozatot tárolja, az üres sorozatot is.

## Azonosító-metaváltozók

Az osztály-, függvény-, interfész-, trait- és enumnevek azonosítók, nem kifejezések, ezért a PHP normál esetben nem fogadná el utánuk a `$Name` elemet a `class` után. A Greph elemzés előtt átírja ezeket a mintákat, így a metaváltozó továbbra is működik:

```bash
./vendor/bin/greph -p 'class $NAME extends BaseController {}' src
./vendor/bin/greph -p 'function $NAME(): void {}' src
./vendor/bin/greph -p 'interface $NAME {}' src
```

Ugyanez az átírás történik a `class`, a `interface`, a `trait`, a `enum` és a `function` esetében is.

## Ismétlődő metaváltozók

Ha egy metaváltozót ugyanazon a mintán belül újra felhasznál, azzal előírja, hogy mindkét előfordulásnak szerkezetileg ugyanarra a csomópontra kell illeszkednie. Ez hasznos az ismétlődő kód felismerésére:

```bash
# Tautological comparisons
./vendor/bin/greph -p '$X == $X' src

# Redundant ternaries
./vendor/bin/greph -p '$X ? $X : null' src
```

Ugyanez a szabály érvényes a `$$$VARIADIC` esetében is: a `$$$ARGS` két előfordulásának ugyanarra a sorozatra kell illeszkednie.

## Fájlok szűrése

Az AST-mód ugyanazzal a bejáróval járja be a fájlfát, mint a szöveges mód, és alapértelmezés szerint a `php` fájltípus-szűrőt használja. Felülbírálható a következőkkel: `--type`, `--type-not`, `--glob`, `--no-ignore` és `--hidden`. A bejáró továbbra is figyelembe veszi a `.gitignore` és a `.grephignore` értékét, és kihagyja a bináris fájlokat.

```bash
./vendor/bin/greph -p 'new $CLASS()' --glob 'src/**/*.php' .
./vendor/bin/greph -p 'new $CLASS()' --type-not phpt src
```

## Kimenet

Az alapértelmezett kimenet a szöveges módéval megegyező `file:line:content` formátumot használja, a megtalált kódot egyetlen sorba tömörítve:

```text
src/Greph.php:38:return (new FileWalker())->walk($paths, $options);
src/Greph.php:49:$searcher = new TextSearcher();
```

Strukturált találatok kibocsátásához adja meg a `--json` jelzőt:

```json
[
  {
    "file": "src/Greph.php",
    "start_line": 38,
    "end_line": 38,
    "start_file_pos": 1234,
    "end_file_pos": 1252,
    "code": "new FileWalker()"
  }
]
```

## Elemzési hibák

Alapértelmezés szerint a Greph csendben kihagyja az elemzés során hibát okozó fájlokat. Ez megfelelő viselkedés nagy kódbázisok vizsgálatakor, amelyek kísérleti vagy generált PHP kódot is tartalmaznak. Az elemzési hiba jelzéséhez adja meg a `--strict-parse` értéket (a `greph-index ast-index search` és a `greph-index ast-cache search` esetén), vagy használja közvetlenül a homlokzatot, és állítsa be a `skipParseErrors: false` értéket a `AstSearchOptions` objektumon.

## Programozott használat

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

$matches = Greph::searchAst(
    '$obj->$method($$$ARGS)',
    'src',
    new AstSearchOptions(jobs: 4),
);

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

    foreach ($match->captures as $name => $node) {
        echo "  {$name} = " . get_debug_type($node) . "\n";
    }
}
```

A `$match->node` a rögzített `PhpParser\Node` (így a PHP-Parser `NodeVisitor` segítségével bejárhatja), a `$match->captures` pedig minden metaváltozó nevét a hozzá tartozó rögzített csomópontra vagy csomópontlistára képezi le.

## Működés

A folyamat lépései:

1. **Mintafeldolgozás**: a `Greph\Ast\PatternParser` átírja az azonosító-metaváltozókat, majd elemzi a mintát a PHP-Parser segítségével.
2. **Forráskód feldolgozása**: minden jelölt fájl egyszer kerül elemzésre. `ast-cache` módban ezt a lépést a gyorsítótárból történő visszafejtés váltja fel.
3. **Jelöltek szűrése**: a `Greph\Ast\AstPatternPrefilter` durva aláírást nyer ki a mintából (hívásnév, osztálynév, utasítástípus), és ezzel kihagyja azokat a fájlokat, amelyek nyilvánvalóan nem tartalmazhatnak találatot. `ast-index` módban ehelyett egy előre kiszámított tényadattárban végez lekérdezést.
4. **Illesztés**: a `Greph\Ast\PatternMatcher` bejárja a forrás AST-jét, és összeveti a minta AST-jével; közben hozzárendeli a metaváltozókat, és ellenőrzi, hogy az ismétlődő változók következetesek-e.
5. **Eredmény kibocsátása**: az illesztett csomópontok `AstMatch` objektumokká alakulnak sor- és bájtpozíciókkal, valamint az eredeti forrás megfelelő részletével.

Ismétlődő munkaterhelésnél az [indexelt AST-keresés](https://greph.inline0.dev/hu/docs/indexed/ast) és a [gyorsítótárazott AST-keresés](https://greph.inline0.dev/hu/docs/indexed/cache) kihagyja a 2. és 3. lépés nagy részét.
