如何在 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 = _POST
和 new = nonexist
我使用 leavenode
函数到达 _POST
和 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 => 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]
元素包含 =
左侧涉及的所有变量。
我正在使用 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 = _POST
和 new = nonexist
我使用 leavenode
函数到达 _POST
和 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 => 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]
元素包含 =
左侧涉及的所有变量。