PHP 7.4升级至8.2:用Rector自动修复Undefined Array Key警告
解决PHP 8.2中"undefined array key"警告的Rector自动化修复方案
针对PHP 7.4迁移至8.2后出现的大量"undefined array key"警告,以下是对应你提出的四个场景的Rector自定义规则实现方案:
场景1、2:补全数组初始化时缺失的键
这类场景的核心是在数组定义或+=合并操作中,自动添加代码中已访问但未初始化的键,默认赋值为null。
自定义Rector规则代码
use PhpParser\Node; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\AssignOp\Plus; use PhpParser\Node\Stmt\ClassMethod; use Rector\Core\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; final class CompleteUndefinedArrayKeysRector extends AbstractRector { public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( '补全数组初始化中缺失的、代码中已访问的键,默认赋值为null', [ new CodeSample( <<<'CODE_SAMPLE' $options = ['key1' => 'key1Value']; echo $options['key2']; CODE_SAMPLE , <<<'CODE_SAMPLE' $options = ['key1' => 'key1Value', 'key2' => null]; echo $options['key2']; CODE_SAMPLE ), ] ); } /** * @return array<class-string<Node>> */ public function getNodeTypes(): array { return [Assign::class, Plus::class]; } /** * @param Assign|Plus $node */ public function refactor(Node $node): ?Node { if (!$node->var instanceof Node\Expr\Variable) { return null; } $arrayVarName = $this->getName($node->var); if ($arrayVarName === null) { return null; } $accessedKeys = []; $parentMethod = $this->betterNodeFinder->findParentType($node, ClassMethod::class); if (!$parentMethod instanceof ClassMethod) { return null; } $this->traverseNodesWithCallable((array)$parentMethod->stmts, function (Node $subNode) use ($arrayVarName, &$accessedKeys) { if (!$subNode instanceof ArrayDimFetch) { return null; } if (!$subNode->var instanceof Node\Expr\Variable || $this->getName($subNode->var) !== $arrayVarName) { return null; } if (!$subNode->dim instanceof Node\Scalar\String_) { return null; } $key = $subNode->dim->value; $accessedKeys[$key] = true; }); $currentArray = $node instanceof Assign ? $node->expr : $node->expr; if (!$currentArray instanceof Array_) { return null; } $currentKeys = []; foreach ($currentArray->items as $item) { if (!$item->key instanceof Node\Scalar\String_) { continue; } $currentKeys[$item->key->value] = true; } foreach ($accessedKeys as $key => $_) { if (!isset($currentKeys[$key])) { $newItem = new Node\Expr\ArrayItem( new Node\Expr\ConstFetch(new Node\Name('null')), new Node\Scalar\String_($key) ); $currentArray->items[] = $newItem; } } return $node; } }
场景3、4:给条件判断中的数组访问添加空合并运算符
这类场景需要识别条件表达式中的数组键访问,自动包裹?? null避免警告。
自定义Rector规则代码
use PhpParser\Node; use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\BinaryOp\Coalesce; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Name; use PhpParser\Node\Stmt\If_; use Rector\Core\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; final class WrapArrayDimFetchInCoalesceRector extends AbstractRector { public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( '给条件判断中的数组键访问添加?? null,避免undefined array key警告', [ new CodeSample( <<<'CODE_SAMPLE' if ($options['key2']) { echo $options['key2']; } CODE_SAMPLE , <<<'CODE_SAMPLE' if ($options['key2'] ?? null) { echo $options['key2']; } CODE_SAMPLE ), ] ); } /** * @return array<class-string<Node>> */ public function getNodeTypes(): array { return [If_::class]; } /** * @param If_ $node */ public function refactor(Node $node): ?Node { $this->traverseNodesWithCallable([$node->cond], function (Node $subNode) { if (!$subNode instanceof ArrayDimFetch) { return null; } if ($subNode->getAttribute('already_wrapped')) { return null; } $coalesce = new Coalesce( $subNode, new ConstFetch(new Name('null')) ); $subNode->setAttribute('already_wrapped', true); return $coalesce; }); return $node; } }
使用说明
- 将上述两个规则放入你的Rector项目的
src/Rector目录下,替换命名空间为你的项目命名空间 - 在
rector.php中注册规则:
use Rector\Config\RectorConfig; return static function (RectorConfig $rectorConfig): void { $rectorConfig->rule(\YourProjectNamespace\CompleteUndefinedArrayKeysRector::class); $rectorConfig->rule(\YourProjectNamespace\WrapArrayDimFetchInCoalesceRector::class); };
- 运行Rector命令执行修复:
vendor/bin/rector process src
注意:当前规则仅处理字符串类型的数组键,若需支持数字键等其他类型,可修改对应节点判断逻辑。
内容的提问来源于stack exchange,提问作者Chirag Kalani
相关产品推荐
相关产品推荐

