rectorphp/rector · error · ShouldNotHappenException

"%s" rule is deprecated, as it is a personal preference that

Error message

"%s" rule is deprecated, as it is a personal preference that makes foreach harder to read and extend

What it means

UnusedForeachValueToArrayKeysRector used to rewrite foreach ($items as $key => $_) { ... } that ignores the value into foreach (array_keys($items) as $key) { ... }. It is deprecated because the transformation is a personal preference that makes the foreach harder to read and extend (you lose direct access to the value if the loop body grows). Its refactor() now throws ShouldNotHappenException on any StmtsAware node visit; the rule is dead code kept only to surface stale configuration.

Source

Thrown at rules/CodeQuality/Rector/Foreach_/UnusedForeachValueToArrayKeysRector.php:58

        }
    }
}
CODE_SAMPLE
)]);
    }
    /**
     * @return array<class-string<Node>>
     */
    public function getNodeTypes(): array
    {
        return NodeGroup::STMTS_AWARE;
    }
    /**
     * @param StmtsAware $node
     */
    public function refactor(Node $node): ?Node
    {
        throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as it is a personal preference that makes foreach harder to read and extend', self::class));
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove UnusedForeachValueToArrayKeysRector::class from rector.php / imported sets and re-run dry-run
  2. Leave foreach ($items as $key => $_) as is — it is perfectly readable and no upgrade requires changing it
  3. If you prefer array_keys() style, convert the few sites manually
  4. Check for the rule name in shared set packages your config imports

Example fix

// before (rector.php)
->withRules([
    \Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector::class,
])

// after
// rule deleted from config; loop style stays:
foreach ($items as $key => $_) {
    // uses $key only
}
Defensive patterns

Strategy: validation

Validate before calling

$deprecated = ['UnusedForeachValueToArrayKeysRector'];
foreach (glob(__DIR__ . '/rector*.php') as $config) {
    $src = file_get_contents($config);
    foreach ($deprecated as $rule) {
        if (str_contains($src, $rule)) {
            fwrite(STDERR, "Remove deprecated rule {$rule} from {$config}\n");
            exit(1);
        }
    }
}

Prevention

When it happens

Trigger: Registering rules/CodeQuality/Rector/Foreach_/UnusedForeachValueToArrayKeysRector.php in the config and running process/dry-run over any statement-level node (the rule matches NodeGroup::STMTS_AWARE, i.e. functions, methods, namespaces — virtually every file). The throw comes from rules/CodeQuality/Rector/Foreach_/UnusedForeachValueToArrayKeysRector.php:58.

Common situations: A legacy rector.php with a granular CodeQuality whitelist still naming this rule after a Rector upgrade. Because the node type is every statement container, the very first file analysed crashes, making it look like a Rector bug rather than a config problem.

Related errors


AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21). Data as JSON: /api/errors/88a8aa739e6ac93e. Report an issue: GitHub.