Liigu sisu juurde

AST-otsing

Greph AST-režiim otsib PHP lähtekoodi struktuuri, mitte teksti järgi. Mustrid kirjutatakse tavalise PHP koodina koos $VARIABLE ja $$$VARIADIC metamärkidega. Muster parsitakse nikic/php-parser abil samakujuliseks AST-puuks nagu lähtekood, millest otsitakse, ning seejärel sobitatakse sõlmhaaval.

See kasutab sama mudelit nagu ast-grep ning sg ühilduvuskest pakub sama mootori peal ast-grep CLI-liidest.

Kiired näited

Shell
# 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

Mustri süntaks

Muster on kehtiv PHP lähtekood. Kõikjal, kus võiks olla päris avaldis või lause, saate selle sõlme hõivamiseks asendada metamärgi.

Süntaks Sobitub Näide
$VAR Mis tahes üksik AST-sõlm, hõivatud kui VAR $x + $y sobitub mustriga foo() + bar
$_ Mis tahes üksik AST-sõlm, mida ei hõivata $_->method() sobitub mis tahes vastuvõtjaga
$$$ARGS Null või rohkem sõlmi (muutliku pikkusega), hõivatud kui ARGS func($$$ARGS) sobitub mustriga func(), func(1), func(1, 2, 3)
$VAR (korduv) Sama $VAR peab mõlemal korral sobituma sama struktuuriga $x == $x sobitub mustriga a == a, mitte a == b

Metamuutuja nimi algab tava kohaselt suurtähega, kuid see pole kohustuslik. $_ on hõivamiseta metamärk.

$$$VARIADIC töötab seal, kus PHP lubab sõlmede loendit: funktsiooniargumendid, massiivi elemendid, parameetriloendid ja lausete kehad. Hõive salvestab kogu sobitatud jada (ka siis, kui see on tühi).

Identifikaatori metamärgid

Klasside, funktsioonide, liideste, trait'ide ja enum'ite nimed on identifikaatorid, mitte avaldised, seega PHP ei aktsepteeriks tavaliselt $Name pärast class. Greph kirjutab need mustrid enne parsimist ümber, nii et metamärk toimib endiselt:

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

Sama ümberkirjutamine toimub järgmiste puhul: class, interface, trait, enum ja function.

Korduvad metamärgid

Metamärgi korduv kasutamine samas mustris eeldab, et mõlemad esinemiskohad sobituvad struktuurselt sama sõlmega. See aitab leida üleliigset koodi:

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

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

Sama reegel kehtib $$$VARIADIC kohta: kaks $$$ARGS esinemiskohta peavad sobituma sama jadaga.

Failide filtreerimine

AST-režiim läbib failipuu tekstiotsinguga sama läbikäijaga ning kasutab vaikimisi failitüübi filtrit php. Alistage see valikutega --type, --type-not, --glob, --no-ignore ja --hidden. Läbikäija järgib endiselt .gitignore ja .grephignore ning jätab binaarfailid vahele.

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

Väljund

Vaikimisi kasutab väljund sama vormingut file:line:content nagu tekstiotsingus ning koondab sobitatud koodi ühele reale:

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

Struktureeritud vastete väljastamiseks edastage --json:

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

Parsimisvead

Vaikimisi jätab Greph vaikselt vahele failid, mida ei saa parsida. See on sobiv käitumine suure koodibaasi puhul, kus leidub eksperimentaalset või genereeritud PHP-i. Parsimisvea väljastamiseks edastage --strict-parse (valikutele greph-index ast-index search ja greph-index ast-cache search) või määrake skipParseErrors: false väärtus suvandile AstSearchOptions, kui kasutate fassaadi otse.

Programmipõhine kasutus

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";
    }
}

$match->node on hõivatud PhpParser\Node (nii et saate seda läbida PHP-Parser NodeVisitor abil) ning $match->captures vastendab iga metamärgi nime hõivatud sõlmele või sõlmede loendile.

Kuidas see töötab

Töövoog on järgmine:

  1. Mustri parsimine: Greph\Ast\PatternParser kirjutab identifikaatorite metamärgid ümber ja seejärel parsib mustri valikuga PHP-Parser.
  2. Lähtekoodi parsimine: iga kandidaatfail parsitakse üks kord. ast-cache režiimis asendab selle sammu hoidlast deserialiseerimine.
  3. Kandidaatide filtreerimine: Greph\Ast\AstPatternPrefilter eraldab mustrist ligikaudse signatuuri (väljakutse nimi, klassi nimi, lausetüüp) ja kasutab seda failide vahelejätmiseks, kui need ilmselgelt vastet sisaldada ei saa. ast-index režiimis küsitakse selle asemel eelarvutatud faktide hoidlast.
  4. Sobitamine: Greph\Ast\PatternMatcher läbib lähtekoodi AST-puu ja võrdleb seda mustri AST-puuga, seob seejuures metamärgid ning kontrollib korduvate muutujate kooskõla.
  5. Tulemuste väljastamine: sobitatud sõlmed teisendatakse AstMatch objektideks, mis sisaldavad rea- ja baidipositsioone ning lähtekoodi algset lõiku.

Korduvate töökoormuste korral jätavad indekseeritud AST-otsing ja vahemällu salvestatud AST-otsing enamiku sammudest 2 ja 3 vahele.