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
- Remove UnusedForeachValueToArrayKeysRector::class from rector.php / imported sets and re-run dry-run
- Leave foreach ($items as $key => $_) as is — it is perfectly readable and no upgrade requires changing it
- If you prefer array_keys() style, convert the few sites manually
- 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
- Check the Rector changelog when upgrading; remove rules marked deprecated the same day
- Do not copy granular rule whitelists from tutorials; import curated sets instead
- Keep foreach style decisions in code review, not in automated rewriting
- Run vendor/bin/rector dry-run in CI to catch stale registrations before they hit developers
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
- "%s" is deprecated as depends on context and personal prefer
- "%s" is deprecated, as simplifying regex ranges is a persona
- "%s" rule is deprecated, as it is a personal preference that
- "%s" rule is deprecated, as it covers a very specific shape
- "%s" is deprecated as noisy change with little value. Use ma
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/88a8aa739e6ac93e.
Report an issue: GitHub.