Pencarian AST
Mode AST milik Greph mencari struktur sumber PHP, bukan teks. Pola ditulis sebagai kode PHP biasa dengan metavariabel $VARIABLE dan $$$VARIADIC. Pola diurai oleh nikic/php-parser menjadi bentuk AST yang sama dengan sumber yang dicari, lalu dicocokkan simpul demi simpul.
Model ini sama dengan ast-grep, dan pembungkus kompatibilitas sg menyediakan antarmuka ast-grep CLI di atas mesin yang sama.
Contoh singkat
# 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
Sintaks pola
Pola adalah sumber PHP yang valid. Di mana pun ekspresi atau pernyataan biasa dapat ditempatkan, Anda dapat menggantinya dengan metavariabel untuk menangkap simpul tersebut.
| Sintaks | Cocok dengan | Contoh |
|---|---|---|
$VAR |
Simpul AST tunggal apa pun, ditangkap sebagai VAR |
$x + $y cocok dengan foo() + bar |
$_ |
Simpul AST tunggal apa pun, tanpa ditangkap | $_->method() cocok dengan penerima apa pun |
$$$ARGS |
Nol atau lebih simpul (variadik), ditangkap sebagai ARGS |
func($$$ARGS) cocok dengan func(), func(1), func(1, 2, 3) |
$VAR (berulang) |
$VAR yang sama harus cocok dengan struktur yang sama pada kedua kemunculan |
$x == $x cocok dengan a == a, bukan a == b |
Nama metavariabel biasanya menggunakan huruf besar, tetapi tidak harus. $_ adalah wildcard yang tidak menangkap.
$$$VARIADIC berfungsi di mana pun PHP mengizinkan daftar simpul: argumen fungsi, item array, daftar parameter, isi pernyataan. Tangkapan menyimpan seluruh urutan yang cocok, termasuk jika tidak ada item.
Metavariabel pengenal
Nama kelas, fungsi, antarmuka, trait, dan enum adalah pengenal, bukan ekspresi, sehingga PHP biasanya tidak menerima $Name setelah class. Greph menulis ulang pola ini sebelum penguraian agar metavariabel tetap berfungsi:
./vendor/bin/greph -p 'class $NAME extends BaseController {}' src
./vendor/bin/greph -p 'function $NAME(): void {}' src
./vendor/bin/greph -p 'interface $NAME {}' src
Penulisan ulang yang sama terjadi untuk class, interface, trait, enum, dan function.
Metavariabel berulang
Menggunakan kembali metavariabel di dalam pola yang sama menyatakan bahwa kedua kemunculannya harus cocok secara struktural dengan simpul yang sama. Ini berguna untuk menemukan kode yang berlebihan:
# Tautological comparisons
./vendor/bin/greph -p '$X == $X' src
# Redundant ternaries
./vendor/bin/greph -p '$X ? $X : null' src
Aturan yang sama berlaku untuk $$$VARIADIC: dua kemunculan $$$ARGS harus cocok dengan urutan yang sama.
Memfilter file
Mode AST menelusuri pohon file dengan walker yang sama seperti mode teks dan secara default menggunakan filter jenis file php. Ganti dengan --type, --type-not, --glob, --no-ignore, dan --hidden. Walker tetap mematuhi .gitignore dan .grephignore serta melewati file biner.
./vendor/bin/greph -p 'new $CLASS()' --glob 'src/**/*.php' .
./vendor/bin/greph -p 'new $CLASS()' --type-not phpt src
Output
Output default menggunakan format file:line:content yang sama seperti mode teks, dengan kode yang cocok diringkas menjadi satu baris:
src/Greph.php:38:return (new FileWalker())->walk($paths, $options);
src/Greph.php:49:$searcher = new TextSearcher();
Berikan --json untuk menghasilkan kecocokan terstruktur:
[
{
"file": "src/Greph.php",
"start_line": 38,
"end_line": 38,
"start_file_pos": 1234,
"end_file_pos": 1252,
"code": "new FileWalker()"
}
]
Error penguraian
Secara default, Greph diam-diam melewati file yang gagal diurai. Perilaku ini tepat saat menjalankan pencarian pada basis kode besar yang berisi PHP eksperimental atau yang dihasilkan otomatis. Berikan --strict-parse (pada greph-index ast-index search dan greph-index ast-cache search) untuk memunculkan error penguraian, atau tetapkan skipParseErrors: false pada AstSearchOptions saat menggunakan facade secara langsung.
Penggunaan secara terprogram
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 adalah PhpParser\Node yang ditangkap (sehingga Anda dapat menelusurinya dengan PHP-Parser milik NodeVisitor), dan $match->captures memetakan setiap nama metavariabel ke simpul atau daftar simpul yang ditangkap.
Cara kerjanya
Pipeline-nya adalah:
- Penguraian pola:
Greph\Ast\PatternParsermenulis ulang metavariabel pengenal, lalu mengurai pola dengan PHP-Parser. - Penguraian sumber: setiap file kandidat diurai satu kali. Dalam mode
ast-cache, langkah ini digantikan dengan deserialisasi dari penyimpanan cache. - Pemfilteran kandidat:
Greph\Ast\AstPatternPrefiltermengekstrak tanda tangan kasar dari pola (nama pemanggilan, nama kelas, jenis pernyataan) dan menggunakannya untuk melewati file yang jelas tidak mungkin memuat kecocokan. Dalam modeast-index, langkah ini justru mengueri penyimpanan fakta yang telah dihitung sebelumnya. - Pencocokan:
Greph\Ast\PatternMatchermenelusuri AST sumber dan membandingkannya dengan AST pola, mengikat metavariabel dan memastikan konsistensi variabel berulang. - Penghasilan hasil: simpul yang cocok diubah menjadi objek
AstMatchdengan posisi baris/byte dan potongan sumber asli.
Untuk beban kerja berulang, pencarian AST terindeks dan pencarian AST dalam cache melewati sebagian besar langkah 2 dan 3.