
# AST-Suche mit Cache

Die AST-Suche mit Cache ist ein ergänzender Modus mit aufgewärmtem Cache zum [Faktenindex](https://greph.inline0.dev/de/docs/indexed/ast). Statt extrahierte Fakten zu speichern und passende Dateien erneut zu parsen, speichert der Cache serialisierte geparste Bäume auf der Festplatte. Bei späteren Abfragen werden die Bäume deserialisiert und direkt mit dem Matcher geprüft. Die PHP-Parser-Pipeline wird dabei vollständig übersprungen.

Du erreichst den Cache über den Unterbefehl `greph-index ast-cache` CLI und die Fassadenmethoden `Greph::buildAstCache()` / `Greph::searchAstCached()`. Auch Suchen über mehrere Indizes und manifestbasierte Gruppen werden unterstützt.

## Cache erstellen

```bash
# Full build at the current directory
./vendor/bin/greph-index ast-cache build .

# Use a non-default cache directory
./vendor/bin/greph-index ast-cache build . --index-dir /tmp/greph-ast-cache

# Build a cache that may refresh automatically for small changes
./vendor/bin/greph-index ast-cache build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
```

Standardmäßig wird der Cache unter `<root>/.greph-ast-cache/` gespeichert. Von den drei Indexmodi dauert die Erstellung dieses Caches meist am längsten, da jede Datei einmal geparst werden muss.

Nach erfolgreicher Erstellung wird eine einzeilige Zusammenfassung ausgegeben:

```text
Built AST cache for 2547 files in .greph-ast-cache (2541 cached trees, +2541 ~0 -0 =0)
```

Die Anzahl gespeicherter Bäume ist üblicherweise etwas geringer als die Anzahl der Dateien, da Dateien mit Parse-Fehlern stillschweigend übersprungen werden und keinen Cache-Eintrag erhalten. Übergib `--strict-parse` beim Suchbefehl, wenn Parse-Fehler stattdessen angezeigt werden sollen.

## Cache aktualisieren

```bash
./vendor/bin/greph-index ast-cache refresh .
```

`refresh` durchsucht den indexierten Stammordner erneut, parst geänderte Dateien neu und schreibt nur die veränderten Bäume im Cache um.

Die Lebenszyklusprofile entsprechen den anderen aufgewärmten Modi:

- `static`: Aktualität nie prüfen oder automatisch ändern
- `manual-refresh`: veralteten Zustand in `stats` melden, aber bei der Suche nie aktualisieren
- `opportunistic-refresh`: bei der Suche nur aktualisieren, wenn die Zahl geänderter Dateien unter den konfigurierten Grenzwerten liegt
- `strict-stale-check`: veraltete Suchen ablehnen, anstatt den Cache zu aktualisieren

## Cache abfragen

```bash
./vendor/bin/greph-index ast-cache search 'new $CLASS()' src
./vendor/bin/greph-index ast-cache search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-cache search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-cache search --fallback scan 'new $CLASS()' src
./vendor/bin/greph-index ast-cache search --trace-plan 'array($$$ITEMS)' src
```

Die verfügbaren Flags entsprechen denen von [`ast-index search`](https://greph.inline0.dev/de/docs/indexed/ast#querying-the-index), einschließlich `--fallback scan` für fehlende Caches.

### Cache-Suche über mehrere Indizes

Wiederhole `--index-dir`, um mehrere aufgewärmte Caches in einem Aufruf zu durchsuchen:

```bash
./vendor/bin/greph-index ast-cache search \
  --index-dir ../wordpress/.greph-ast-cache \
  --index-dir ./.greph-ast-cache \
  --show-index-origin \
  'array($$$ITEMS)' .
```

### Manifestbasierte Cache-Gruppen

Wenn du bereits benannte Gruppen aufgewärmter Indizes verwendest, kannst du mit demselben Manifest die AST-Suche mit Cache ausführen:

```bash
./vendor/bin/greph-index set build --mode ast-cache
./vendor/bin/greph-index set stats --mode ast-cache --dry-refresh
./vendor/bin/greph-index set search --mode ast-cache --show-index-origin 'array($$$ITEMS)' .
```

### Planner-Diagnosen

`--trace-plan` gibt die Entscheidungen des AST-Cache-Planners an `stderr` aus. Dazu gehören:

- welche aufgewärmten Caches durchsucht wurden
- ob die Logik zur Aktualisierung veralteter Caches ausgeführt wurde
- die Anzahl der Kandidatendateien nach der Eingrenzung auf Dateiebene
- die Anzahl der deserialisierten Bäume, die für den genauen strukturellen Abgleich verwendet wurden

## Cache oder Faktenindex

Beide Modi beschleunigen die AST-Suche, sind aber auf unterschiedliche Aufgaben ausgelegt.

| Aspekt | Faktenindex (`ast-index`) | Cache (`ast-cache`) |
|---|---|---|
| Gespeicherte Daten | Extrahierte Fakten (Aufrufnamen, Klassennamen, Deklarationen) | Serialisierte geparste Bäume |
| Erstellungskosten | Niedriger | Höher (parst alles) |
| Größe beim Erstellen | Kleiner | Größer |
| Abfragepfad | Nach Fakten filtern, dann Kandidaten parsen und abgleichen | Baum deserialisieren, dann abgleichen |
| Am besten geeignet für | Muster mit einem erkennbaren Kopf (Aufrufname, Klassenname) | Muster, deren Unterscheidungsmerkmal strukturell und nicht namentlich ist |
| Am schlechtesten geeignet für | Muster, deren Kopf eine Metavariable ist | Kalte Abfragen für einen Baum, der nicht mehr in den OS-Seitencache passt |

In der Praxis bietet der Faktenindex die schnellste kalte Abfrage und der Cache die schnellste warme Abfrage. Wähle die Variante, die zu deinem Workload passt, oder erstelle beide und lass dein Tool entscheiden.

## Programmatische Verwendung

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

Greph::buildAstCache('.', lifecycle: IndexLifecycleProfile::Static);

$matches = Greph::searchAstCached(
    'array($$$ITEMS)',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);
```

`searchAstCached` akzeptiert dieselben `AstSearchOptions` wie die native AST-Suche und liefert dieselbe `list<AstMatch>`-Struktur zurück. Der einzige Unterschied: Für Dateien, die bereits im Cache liegen, wird die Parser-Pipeline umgangen. Für Abläufe mit mehreren Indizes oder Manifesten verwendest du `searchAstCachedMany(...)` und `searchAstCachedSet(...)`.

## Wann du ihn verwenden solltest

Der Cache-Modus für ASTs ist das richtige Werkzeug, wenn:

- Du wiederholt strukturelle Abfragen an derselben Codebasis ausführst.
- Bei deinen vorherigen Durchläufen PHP-Parser der Engpass war (in Profilen als Zeit im Lexer und Parser sichtbar).
- Du den Speicherplatz für den serialisierten Baumspeicher entbehren kannst.

Wenn deine Abfragen normalerweise nur einen kleinen Teil der Codebasis betreffen und sich die Treffer auf erkennbare Aufruf- oder Klassennamen konzentrieren, ist der [Faktenindex](https://greph.inline0.dev/de/docs/indexed/ast) meist besser geeignet. Wenn deine Abfragen große Teile der Codebasis abdecken und du einmalige Parsing-Kosten in Kauf nehmen kannst, ist der Cache die bessere Wahl.
