什麼是 PHP AST
AST(Abstract Syntax Tree/抽象語法樹)是將原始碼分解為「具有意義的結構」的樹狀結構。 當您要建立程式碼生成工具、靜態分析工具或自動重構工具時,AST 幾乎是必要基礎。即便是字串替換容易出錯的變換,透過 AST 也能以「function call」、「class declaration」、「use statement」這類語法單位安全處理。
PHP 的內部 AST
PHP 7 以後的 Zend Engine 並非直接將 PHP 程式碼轉為 opcode,而是先轉為內部 AST 再進行編譯。- 即使是以
php -r執行的單行程式碼,內部也走相同的編譯管道 - OPcache 會快取並重複使用最終產生的 opcode
- 於一般應用程式開發中,幾乎沒有直接操作此內部 AST 的機會
nikic/PHP-Parser 套件
nikic/PHP-Parser 是用於解析、走訪、再生 PHP 程式碼為 AST 的標準函式庫。README 與官方文件說明其基本步驟有下列 3 步。安裝
基本 parse 範例(將程式碼轉為 AST)
以 NodeVisitor 模式走訪、變更 AST
NodeVisitorAbstract 後,只需實作所需的 hook(enterNode / leaveNode)。於複雜的變換中,於 enterNode 蒐集資訊、於 leaveNode 置換的流程頗為有效。
以 Pretty Printer 再生程式碼
Laravel/Chisel 的使用範例
laravel/chisel 是於後處理階段裁剪啟動套件的函式庫。於composer.json 中將 nikic/php-parser 5.x 系列納入相依。
於 Chisel 的 Laravel\Chisel\Ast\Source 中,以下列步驟執行 AST 編輯。
- 以
ParserFactory::createForNewestSupportedVersion()解析程式碼 - 於
NodeTraverser加入多個 Visitor(如RemoveImportVisitor)進行變換 - 以
PhpParser\PrettyPrinter\Standard的printFormatPreserving()保持原格式並寫回
use 敘述、trait、interface。
使用情境
使用 AST 較容易推動下列開發。- 程式碼生成 CLI(於樣板建立後以語法單位編輯)
- 靜態分析工具(偵測特定語法、偵測違反規則)
- 自動重構(API 遷移或命名變更的半自動化)
- 專案範本的後處理(如 Chisel 的功能刪除、置換)
總結
PHP AST 於一般 Laravel 應用程式開發並非每日使用的功能。 不過若您要推動工具開發或套件開發,AST 是實現「不易損壞且具再現性的程式碼變更」的強力基礎。首先請以小型 CLI 試用nikic/php-parser 的 Parser、Visitor、Pretty Printer 三者。