如何在 AST 中获取变量名和值

How to get variable name and value in AST

我正在使用 PHP-PArser 查找 PHP 程序的 AST。例如:

代码

<?php
use PhpParser\Error;
use PhpParser\NodeDumper;
use PhpParser\ParserFactory;

$code = <<<'CODE'
<?php
$variable = $_POST['first'];
$new = $nonexist; 
CODE;

$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try {
    $ast = $parser->parse($code);
} catch (Error $error) {
    echo "Parse error: {$error->getMessage()}\n";
    return;
}

$dumper = new NodeDumper;
echo $dumper->dump($ast) . "\n";

上面例子的AST结果如下:

array( 0: Stmt_Expression( expr: Expr_Assign( var: Expr_Variable( name: variable ) expr: Expr_ArrayDimFetch( var: Expr_Variable( name: _POST_first_symbol ) dim: Scalar_String( value: first ) ) ) ) 1: Stmt_Expression( expr: Expr_Assign( var: Expr_Variable( name: new ) expr: Expr_Variable( name: nonexist ) ) ) )

我要查找的是 variable = _POSTnew = nonexist 我使用 leavenode 函数到达 _POSTvariable。我查找 _POSTvariable 的代码如下:

public function leaveNode(Node $node)
    {
        $collect_to_print= array();

        if ($node instanceof ArrayDimFetch
            && $node->var instanceof Variable
            && $node->var->name === '_POST')
        {
            $variableName = (string) $node->var->name;
            $collect_to_print[$node->dim->value] = $node->var->name; // will store the variables in array in a way to print them all later such as variable => _POST , how to get the name `variable` in this case
            return $node;
        }
        else
            if ($node instanceof Variable
        && !($node->var->name === '_POST' ))
        {
            $collect_to_print[$node->name] = 'Empty' ;
        }

    }

到目前为止,我的结果在单独的行中显示了每个变量,如下所示:

variable => 
first => _POST  // This _POST should be the value of variable (above)
new => Empty
nonexist => Empty

但是,我希望结果是:

variable => _POST
new => Empty
nonexist => Empty

任何帮助请

这比您提出的其他问题要复杂得多,但了解如何编写它很有趣。

我已经对代码进行了注释,但基本上它会分析代码并查找分配(PhpParser\Node\Expr\Assign 节点的实例)。然后它将它分成左右两部分,并递归地提取两部分中的任何变量。

代码允许在表达式的两边嵌套变量,我更改了示例代码以提供一些更广泛的示例。

代码中的注释(假设您了解解析器如何与节点等一起工作)...

$traverser = new NodeTraverser;

class ExtractVars extends NodeVisitorAbstract {
    private $prettyPrinter = null;

    private $variables = [];
    private $expressions = [];

    public function __construct() {
        $this->prettyPrinter = new PhpParser\PrettyPrinter\Standard;
    }

    public function leaveNode(Node $node) {
        if ( $node instanceof PhpParser\Node\Expr\Assign  ) {
                $assignVars = $this->extractVarRefs ( $node->var );
                // Get string of what assigned to actually is
                $assign = $this->prettyPrinter->prettyPrintExpr($node->var);
                // Store the variables associated with the left hand side
                $this->expressions[$assign]["to"] = $assignVars;
                // Store variables from right
                $this->expressions[$assign][] = $this->extractVarRefs ( $node->expr );
         }
    }

    private function extractVarRefs ( Node $node ) : array  {
        $variableList = [];
        // If it's a variable, store the name
        if ( $node instanceof PhpParser\Node\Expr\Variable )   {
            $variable = $this->prettyPrinter->prettyPrintExpr($node);
            $this->variables[] = $variable;
            $variableList[] = $variable;
        }
        // Look for any further variables in the node
        foreach ( $node->getSubNodeNames() as $newNodeName )   {
            $newNode = $node->$newNodeName;
            if ( $newNode instanceof Node && $newNode->getSubNodeNames())   {
                // Recursive call to extract variables
                $toAdd = $this->extractVarRefs ( $newNode );
                // Add new list to current list
                $variableList = array_merge($variableList, $toAdd);
            }
        }
        return $variableList;
    }

    public function getVariables() : array  {
        return array_unique($this->variables);
    }

    public function getExpressions() : array    {
        return $this->expressions;
    }

}

$varExtract = new ExtractVars();
$traverser->addVisitor ($varExtract);

$traverser->traverse($ast);

print_r($varExtract->getVariables());

print_r($varExtract->getExpressions());

给出的变量列表为...

Array
(
    [0] => $_POST
    [1] => $b
    [3] => $new
    [4] => $nonexist
)

表达式列表为

Array
(
    [$_POST[$b]] => Array
        (
            [to] => Array
                (
                    [0] => $_POST
                    [1] => $b
                )

            [0] => Array
                (
                    [0] => $_POST
                )

        )

    [$new] => Array
        (
            [to] => Array
                (
                    [0] => $new
                )

            [0] => Array
                (
                    [0] => $nonexist
                )

            [1] => Array
                (
                    [0] => $_POST
                    [1] => $b
                )

        )

)

请注意,数组的 [to] 元素包含 = 左侧涉及的所有变量。