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
# 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:
./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:
# 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.
./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:
src/Greph.php:38:return (new FileWalker())->walk($paths, $options);
src/Greph.php:49:$searcher = new TextSearcher();
Struktureeritud vastete väljastamiseks edastage --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
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:
- Mustri parsimine:
Greph\Ast\PatternParserkirjutab identifikaatorite metamärgid ümber ja seejärel parsib mustri valikuga PHP-Parser. - Lähtekoodi parsimine: iga kandidaatfail parsitakse üks kord.
ast-cacherežiimis asendab selle sammu hoidlast deserialiseerimine. - Kandidaatide filtreerimine:
Greph\Ast\AstPatternPrefiltereraldab mustrist ligikaudse signatuuri (väljakutse nimi, klassi nimi, lausetüüp) ja kasutab seda failide vahelejätmiseks, kui need ilmselgelt vastet sisaldada ei saa.ast-indexrežiimis küsitakse selle asemel eelarvutatud faktide hoidlast. - Sobitamine:
Greph\Ast\PatternMatcherläbib lähtekoodi AST-puu ja võrdleb seda mustri AST-puuga, seob seejuures metamärgid ning kontrollib korduvate muutujate kooskõla. - Tulemuste väljastamine: sobitatud sõlmed teisendatakse
AstMatchobjektideks, 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.