如何使用Rector将define常量值替换为$_SERVER数组元素?
解决PHP AST中修改define调用参数的问题
需求
将代码 define('USER','pippo'); 修改为 define('USER', $_SERVER["DB_USER"]);。
问题描述
无法创建第一个参数为字符串、第二个参数为$_SERVER["DB_USER"]数组元素的新FuncCall节点;尝试的以下 workaround 代码无效:
if ($node->args[0]->value->value == "USER") { if (!$node->args[1]->value instanceof Node\Scalar\String_) { return null; } $node->args[1]->value->value = "\$_SERVER[\"_DB_USER\"]"; return $node; }
目标AST节点结构
表达式: Expr_FuncCall( 名称: Name( 部分: array( 0: define ) ) 参数: array( 0: Arg( 名称: null 值: Scalar_String( 值: USER ) 引用传递: false 解包: false ) 1: Arg( 名称: null 值: Expr_ArrayDimFetch( 变量: Expr_Variable( 名称: _SERVER ) 索引: Scalar_String( 值: DB_USER ) ) 引用传递: false 解包: false ) ) )
解决方案
你之前的代码错误在于直接修改字符串节点的内容,这只会生成带引号的字符串(比如'$_SERVER["_DB_USER"]'),而不是我们需要的数组元素引用。正确的做法是替换整个第二个参数的节点类型,从Scalar_String换成Expr_ArrayDimFetch。
以下是正确的代码实现:
use PhpParser\Node; // 处理Expr_FuncCall节点 if ($node->name->toString() === 'define' && isset($node->args[0], $node->args[1])) { // 校验第一个参数是值为USER的字符串 if ($node->args[0]->value instanceof Node\Scalar\String_ && $node->args[0]->value->value === 'USER') { // 1. 创建$_SERVER变量节点 $serverVariable = new Node\Expr\Variable('_SERVER'); // 2. 创建数组索引节点(DB_USER字符串) $dbUserKey = new Node\Scalar\String_('DB_USER'); // 3. 组合成$_SERVER["DB_USER"]的ArrayDimFetch节点 $arrayFetchNode = new Node\Expr\ArrayDimFetch($serverVariable, $dbUserKey); // 替换第二个参数的value节点 $node->args[1]->value = $arrayFetchNode; return $node; } } return null;
代码说明
- 先校验当前节点是
define函数调用,且存在两个参数 - 确认第一个参数是值为
USER的字符串节点 - 依次创建
$_SERVER变量节点、DB_USER索引字符串节点,再组合成ArrayDimFetch节点(对应$_SERVER["DB_USER"]) - 将第二个参数的
value替换为新创建的ArrayDimFetch节点,这样生成的代码就是目标形式
内容的提问来源于stack exchange,提问作者realtebo
相关产品推荐
相关产品推荐

