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 elemzi a keresett forrással azonos AST-struktúrára, majd csomópontról csomópontra illeszti.
Ugyanez a modell, mint a ast-grep 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
# 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:
./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:
# 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.
./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:
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:
[
{
"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
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:
- 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. - Forráskód feldolgozása: minden jelölt fájl egyszer kerül elemzésre.
ast-cachemódban ezt a lépést a gyorsítótárból történő visszafejtés váltja fel. - Jelöltek szűrése: a
Greph\Ast\AstPatternPrefilterdurva 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-indexmódban ehelyett egy előre kiszámított tényadattárban végez lekérdezést. - Illesztés: a
Greph\Ast\PatternMatcherbejá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. - Eredmény kibocsátása: az illesztett csomópontok
AstMatchobjektumokká 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 és a gyorsítótárazott AST-keresés kihagyja a 2. és 3. lépés nagy részét.