这里是PHP的新手。我正在使用Parser的尼基奇.
我想删除所有不是Node\Stmt\Function_类型的节点。
目前,我可以通过以下代码来完成这一任务:
$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends NodeVisitorAbstract {
// To leave functions alone
public function enterNode(Node $node) {
if ($node instanceof Node\Stmt\Function_) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
}
// To remove any other nodes that are not 'Function_' type
// Currently can only remove 'If', 'For' and 'Expression' types
public function leaveNode(Node $node) {
if ($node instanceof Node\Stmt\If_ ||
$node instanceof Node\Stmt\For_ ||
$node instanceof Node\Stmt\Expression) {
return NodeTraverser::REMOVE_NODE;
}
}
});但是这将导致一个包含所有不同节点类型的大型if(...||)语句。我尝试使用下面所示的if(!$node instanceof Node\Stmt\Function_),但这将导致错误。我尝试过if(!($node instanceof Node\Stmt\Function_))也有同样的错误。
public function leaveNode(Node $node) {
if (!$node instanceof Node\Stmt\Function_) {
return NodeTraverser::REMOVE_NODE;
}
}#错误:
PHP Fatal error: Uncaught LogicException: leaveNode() returned invalid value of type integer in /usr/local/bin/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:168
Stack trace:
#0 /usr/local/bin/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(146): PhpParser\NodeTraverser->traverseNode()
#1 /usr/local/bin/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(223): PhpParser\NodeTraverser->traverseNode()
#2 /usr/local/bin/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(91): PhpParser\NodeTraverser->traverseArray()
#3 /home/test/Desktop/test.php(130): PhpParser\NodeTraverser->traverse()
#4 {main}
thrown in /usr/local/bin/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php on line 168我理解删除节点只能在leaveNode中实现。因此,我在想,是否有更好的方法来做到这一点,而不是分块巨大的if语句来匹配每一种类型,而不是“Function_”?
谢谢!
编辑让我尝试更多地分享更大的情况以及预期的输入和输出。。
总体情况:我想构建一个程序,当给定PHP代码时,它可以根据请求检索特定的节点(例如,案例、函数、循环)。在这种情况下,它是函数节点。为了做到这一点,我现在正在使用Parser。如果这样做不起作用,我可能会在将来探索使用令牌化。
输入:如下所示的PHP代码示例。
function writeMsg() {
echo "Hello world!";
}
writeMsg();
$x = 5;
if ($x = 5) {
echo "x is 5";
} else {
echo "Something is wrong";
}如果用户希望检索函数节点,则输出将仅仅是包含其内容的函数,而不是其他任何内容:
function writeMsg()
{
echo "Hello world!";
}如果用户希望检索If语句,则输出如下:
if ($x = 5) {
echo "x is 5";
} else {
echo "Something is wrong";
}大图将是检索用户指定的任何类型的节点。不过,就目前而言,函数可以使用。
发布于 2021-02-20 09:57:32
作为另一种解决方案,它在找到函数时从AST中提取函数。这还可以提取类中的函数(使用instanceof Node\Stmt\ClassMethod)以及嵌套函数.
$traverser = new NodeTraverser();
class FunctionExtract extends NodeVisitorAbstract {
// List of functions
public $functionList = [];
public function enterNode(Node $node) {
if ($node instanceof Node\Stmt\Function_
|| $node instanceof Node\Stmt\ClassMethod ) {
$this->functionList[] = $node;
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
}
}
$extract = new FunctionExtract();
$traverser->addVisitor($extract);
$traverser->traverse($ast);
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$newCode = $prettyPrinter->prettyPrintFile($extract->functionList);
echo $newCode;发布于 2021-02-20 08:19:23
经过一些实验,我发现使用节点遍历方法可以工作,但它不能删除代码基础中的语句。
所以代码就像..。
<?php
if ( $a == 1) return;
$b=1;
function test2(string $a): int {
$c = 1;
if ($c == 2) {
$c = 1;
}
return 2;
}用..。
$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends NodeVisitorAbstract {
public function enterNode(Node $node) {
if ($node instanceof Node\Stmt\Function_
|| $node instanceof Node\Stmt\If_ ) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
}
public function leaveNode(Node $node) {
if ($node instanceof Node\Stmt &&
! $node instanceof Node\Stmt\Function_ &&
! $node instanceof Node\Stmt\InlineHTML &&
! $node instanceof Node\Stmt\Class_) {
return NodeTraverser::REMOVE_NODE;
}
}
});产生
<?php
if ($a == 1) {
}
$b = 1;
function test2(string $a) : int
{
$c = 1;
if ($c == 2) {
$c = 1;
}
return 2;
}因此,只有第一个return下的if被删除。
注意,我使用$node instanceof Node\Stmt来表示它是一个语句类型节点,然后只说离开! $node instanceof Node\Stmt\Function_节点。
所以更改为简单地传递原始AST数组并复制任何函数.
$newAst = [];
foreach ( $ast as $node ) {
if ($node instanceof Node\Stmt\Function_) {
$newAst[] = $node;
}
}
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$newCode = $prettyPrinter->prettyPrintFile($newAst);
echo $newCode;发出去..。
<?php
function test2(string $a) : int
{
$c = 1;
if ($c == 2) {
$c = 1;
}
return 2;
}如果只需要函数签名,也可以在复制时重置语句.
$node->stmts = [];
$newAst[] = $node;而你最终会..。
<?php
function test2(string $a) : int
{
}https://stackoverflow.com/questions/66277240
复制相似问题