
# Predpomnjeno iskanje AST

Predpomnjeno iskanje AST je dopolnilni način z ogretim predpomnilnikom k [indeksu dejstev](https://greph.inline0.dev/sl/docs/indexed/ast). Namesto shranjevanja izluščenih dejstev in ponovnega razčlenjevanja ujemajočih se datotek predpomnilnik na disk shrani serializirana razčlenjena drevesa. Pri naslednjih poizvedbah se drevesa deserializirajo in ujemalnik se zažene neposredno, tako da v celoti preskoči cevovod PHP-Parser.

Predpomnilnik je na voljo prek podukaza `greph-index ast-cache` CLI ter fasadnih metod `Greph::buildAstCache()` / `Greph::searchAstCached()`. Podpira tudi iskanje po več indeksih in naborih, podprtih z manifestom.

## Izdelava predpomnilnika

```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
```

Predpomnilnik je privzeto shranjen v `<root>/.greph-ast-cache/`. Izdelava predpomnilnika je običajno najpočasnejša od treh načinov indeksiranja, saj je treba vsako datoteko enkrat razčleniti.

Uspešna izdelava izpiše enovrstični povzetek:

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

Število predpomnjenih dreves je običajno nekoliko manjše od števila datotek, saj datoteke, ki jih ni mogoče razčleniti (in so tiho preskočene), ne ustvarijo vnosa v predpomnilniku. Če želite prikazati napake pri razčlenjevanju, pri ukazu za iskanje podajte `--strict-parse`.

## Osveževanje predpomnilnika

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

`refresh` znova pregleda indeksirano korensko mapo, znova razčleni spremenjene datoteke in prepiše samo spremenjena predpomnjena drevesa.

Profili življenjskega cikla so enaki kot pri drugih ogretih načinih:

- `static`: nikoli samodejno ne preverja svežine ali spreminja
- `manual-refresh`: poroča o zastarelem stanju v `stats`, med iskanjem pa nikoli ne osvežuje
- `opportunistic-refresh`: med iskanjem osveži le, če je nabor sprememb pod nastavljenimi pragovi
- `strict-stale-check`: zavrne zastarela iskanja, namesto da bi jih osvežil

## Poizvedovanje po predpomnilniku

```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
```

Nabor zastavic je enak kot pri [`ast-index search`](https://greph.inline0.dev/sl/docs/indexed/ast#querying-the-index), vključno z `--fallback scan` za manjkajoče predpomnilnike.

### Iskanje po več predpomnilnikih

Ponovite `--index-dir`, da v enem klicu iščete po več ogretih predpomnilnikih:

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

### Nabori predpomnilnikov, podprti z manifestom

Če že uporabljate poimenovane ogrete nabore, lahko isti manifest usmerja iskanje po predpomnjenem AST:

```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)' .
```

### Diagnostika načrtovalnika

`--trace-plan` poroča o odločitvah načrtovalnika predpomnjenega AST za `stderr`, vključno z:

- kateri predpomnilniki so bili pregledani
- ali se je izvedla logika za osveževanje zastarelih podatkov
- število kandidatnih datotek po zožitvi na ravni datotek
- koliko predpomnjenih dreves je bilo deserializiranih za natančno strukturno ujemanje

## Indeks dejstev v primerjavi s predpomnilnikom

Oba načina pospešita iskanje v AST, vendar sta optimizirana za različne vrste opravil.

| Vidik | Indeks dejstev (`ast-index`) | Predpomnilnik (`ast-cache`) |
|---|---|---|
| Kaj je shranjeno | Izluščena dejstva (imena klicev, imena razredov, deklaracije) | Serializirana razčlenjena drevesa |
| Strošek gradnje | Nižji | Višji (razčleni vse) |
| Velikost zgradbe | Manjša | Večja |
| Pot poizvedbe | Filtriranje po dejstvih, nato razčlenitev in ujemanje kandidatov | Deserializacija drevesa, nato ujemanje |
| Najprimernejše za | Vzorce s prepoznavnim začetkom (ime klica, ime razreda) | Vzorce, katerih značilnost je strukturna in ne poimenovalna |
| Najmanj primerno za | Vzorce, katerih začetek je metaspremenljivka | Hladne poizvedbe po drevesu, ki ne sodi več v predpomnilnik strani OS |

V praksi indeks dejstev omogoča najhitrejše hladne poizvedbe, predpomnilnik pa najhitrejše ogrete poizvedbe. Uporabite tistega, ki ustreza vaši obremenitvi, ali zgradite oba in prepustite izbiro svojim orodjem.

## Uporaba v kodi

```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` sprejema enak `AstSearchOptions` kot izvorno iskanje AST in vrne enako obliko `list<AstMatch>`. Edina razlika je, da se za datoteke, ki so že v predpomnilniku, preskoči cevovod razčlenjevalnika. Za poteke z več indeksi ali z manifestom uporabite `searchAstCachedMany(...)` in `searchAstCachedSet(...)`.

## Kdaj jo uporabiti

Način predpomnjenega AST je prava izbira, kadar:

- Večkrat izvajate strukturne poizvedbe nad isto kodno zbirko.
- Ozko grlo pri prejšnjih zagonih je bil PHP-Parser (v profilih je razviden čas, porabljen v leksikalnem analizatorju in razčlenjevalniku).
- Imate dovolj prostora na disku za shrambo serializiranih dreves.

Če vaše poizvedbe običajno zadenejo majhen delež kodne zbirke, zadetki pa se osredotočajo na prepoznavna imena klicev ali razredov, je [indeks dejstev](https://greph.inline0.dev/sl/docs/indexed/ast) običajno primernejša izbira. Če vaše poizvedbe zajamejo širok del kodne zbirke, vendar lahko plačate enkratni strošek razčlenitve, je predpomnilnik boljša izbira.
