为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
茅侃侃 2022-12-11 09:33:59
我正在使用PHP-PARser来查找 PHP 程序的 AST。例如:代码<?phpuse 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 = _POSTANDnew = nonexist 我使用leavenode函数来达到_POSTand variable。我要查找的代码_POST如下variable: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 => Emptynonexist => Empty但是,我希望结果是:variable => _POSTnew => Emptynonexist => Empty请帮忙
查看完整描述

1 回答

?
慕丝7291255

TA贡献1859条经验 获得超6个赞

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


我已经在代码中添加了注释,但基本上它会分析代码并查找分配(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]数组的元素包含 . 左侧涉及的所有变量=。


查看完整回答
反对 回复 2022-12-11
  • 1 回答
  • 0 关注
  • 147 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信