3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
How to Automatically Generate PHP code with PHP-Parser PHP:8.0 nikic/PHP-Parser: 4.12.0 在大型專案中,因為架構極其複雜,所以常會看到有許多由抽象類別、介面實作出來同性質的子物件,比如說 Parser、Extractor 等等。而當依據需求實作出大量又有些微客製化的物件後,如果要一次性調整大量的物件程式碼,比方說修改特定 Variable 的值,就會非常耗費人力。 在這種情況下,我們可以透過 nikic/PHP-Parser 套件達成自動產生 PHP code 的效果。 nikic/PHP-Parser 是一套針對 PHP 設計的 Abstract Syntax Tree(抽象語法樹) 解析工具,除了可以將 PHP code 解析成 AST 之外,也可以透過 AST 產生 PHP code。 Installation nikic/PHP-Parser 透過 Composer 即可安裝。 php composer.phar require nikic/php-parser Basic Usage nikic/PHP-Parser 套件可以分成三個重點: Parse PHP code to AST Visit AST Parse AST to PHP code 這裡舉官方提供的範例,透過實作以上三點,達到動態修改 PHP Function 的功能。 Parse PHP code to AST require 'vendor/autoload.php'; use PhpParser\Error; use PhpParser\NodeDumper; use PhpParser\ParserFactory; // PHP demo function code // 這裡的 test function 會執行 var_dump($foo) $code = <<create(ParserFactory::PREFER_PHP7); try { // 將 PHP code 轉成 AST $ast = $parser->parse($code); } catch (Error $error) { echo "Parse error: {$error->getMessage()}\n"; return; } // Dump 出 AST 結構的字串 // 也可以利用 print_r($ast) 去看各節點物件 $dumper = new NodeDumper; echo $dumper->dump($ast) . PHP_EOL; Visit AST require 'vendor/autoload.php'; use PhpParser\Node; use PhpParser\NodeDumper; use PhpParser\Node\Stmt\Function_; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; // 產生走訪 AST 節點的物件 $traverser = new NodeTraverser(); // 實作走訪時的邏輯(代入 Anonymous Class) $traverser->addVisitor(new class extends NodeVisitorAbstract { public function enterNode(Node $node) { // 遇到是 Function 的節點,就將 Function 內容清空 if ($node instanceof Function_) { $node->stmts = []; } } }); // 代入原 AST 開始走訪,產生新的 AST $ast = $traverser->traverse($ast); // Dump 出 AST 結構 $dumper = new NodeDumper; echo $dumper->dump($ast) . PHP_EOL; Parse AST to PHP code require 'vendor/autoload.php'; use PhpParser\PrettyPrinter; // 產生輸出 PHP code 的物件 $prettyPrinter = new PrettyPrinter\Standard; // 將 AST 轉換成 PHP code echo $prettyPrinter->prettyPrintFile($ast) . PHP_EOL; Practical Usage 這邊再舉一個可能的應用情境,假設 Parser/ 目錄底下有許多實作完成的 Parser 物件,Label01 ~ Label99,而需求是要在特定幾個 Parser 裡的 authorization 加入義大利的區域。 Label Parser 範例 namespace FallZuBallBall\Parser\Label01Parser; class Label01Parser { protected $labelName = 'Label01'; protected $authorization = ['Taiwan' => 'enable', 'Japan' => 'disable']; public function getMetaByAuth(): array { foreach ($this->authorization as $region => $status) { // Do Something } } } AuthTool 透過 nikic/PHP-Parser 實作一個處理此需求的物件。 require_once 'vendor/autoload.php'; namespace FallZuBallBall; use PhpParser\Error; use PhpParser\NodeDumper; use PhpParser\ParserFactory; use PhpParser\Node; use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Scalar\String_; use PhpParser\NodeTraverser; use PhpParser\NodeVisitorAbstract; use PhpParser\PrettyPrinter; class AuthTool { protected $ast; // 設定要 Parse 的 PHP code public function setFile($file): AuthTool { $code = file_get_contents($file); $parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); try { $this->ast = $parser->parse($code); } catch (Error $error) { throw new Exception('Parse error:' . $error->getMessage()); } return $this; } // 可以新增 Auth 資訊到 authorization public function setAuth($region, $status): AuthTool { $traverser = new NodeTraverser(); // 將傳入的變數代入 Anonymous Class $traverser->addVisitor(new class($region, $status) extends NodeVisitorAbstract { protected $region; protected $status; public function __construct($region, $status) { $this->region = $region; $this->status = $status; } public function enterNode(Node $node) { // 尋找到 PropertyProperty 節點 if ($node instanceof \PhpParser\Node\Stmt\PropertyProperty) { // 判斷是否為 authorization if ($node->name->name === 'authorization') { // 加入新的 Auth $item = new ArrayItem(new String_($this->status), new String_($this->region)); $node->default->items[] = $item; } } } }); $this->ast = $traverser->traverse($this->ast); return $this; } public function dumpCode(): string { $prettyPrinter = new PrettyPrinter\Standard; return $prettyPrinter->prettyPrintFile($this->ast); } } 執行 $obj = new AuthTool; $code = $obj->setFile('Parser/Label01Parser.php') ->setAuth('Italy', 'disable') ->dumpCode(); print_r($code); 產生的結果 namespace FallZuBallBall\Parser\Label01Parser; class Label01Parser { protected $labelName = 'Label01'; protected $authorization = ['Taiwan' => 'enable', 'Japan' => 'disable', 'Italy' => 'disable']; public function getMetaByAuth() : array { foreach ($this->authorization as $region => $status) { // Do Something } } } Categories: PHP Tags: PHP 分類 Android AngularJS API Blueprint Chrome Cloud-Solution AWS Azure Database MySQL DataStructure Docker Editor Vim Firefox Git GitLab Google API Hadoop HTTP Language Go Java JavaScript jQuery jQueryChart Node.js Vue Vue-CLI PHP Laravel Lumen ZendFramework Python Mac Network Cisco DLink Juniper Oauth Server Apache Share Unix FreeBSD Linux WebDesign Bootstrap CSS HTML Wordpress Search 搜尋關鍵字:

本文由blogjohnsonluorg提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦