rectorphp/rector · error · ShouldNotHappenException
"%s" rule is deprecated, as inverting nested ifs to continue
Error message
"%s" rule is deprecated, as inverting nested ifs to continue makes the code harder to read and understand
What it means
ChangeNestedForeachIfsToEarlyContinueRector used to invert nested if blocks inside foreach loops into guard continue statements (early-continue style). It is deprecated because inverting nested ifs makes the loop body harder to read and understand — the guard-chain style trades nesting for order-dependence. refactor() now throws ShouldNotHappenException on every Foreach_ node; the rule performs no rewrite and exists only as a deprecation marker.
Source
Thrown at rules/EarlyReturn/Rector/Foreach_/ChangeNestedForeachIfsToEarlyContinueRector.php:71
}
}
}
CODE_SAMPLE
)]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Foreach_::class];
}
/**
* @param Foreach_ $node
*/
public function refactor(Node $node): ?Node
{
throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as inverting nested ifs to continue makes the code harder to read and understand', self::class));
}
}
View on GitHub (pinned to 408fcb0ff1)
Solutions
- Remove ChangeNestedForeachIfsToEarlyContinueRector::class from rector.php and every imported set, then re-run vendor/bin/rector dry-run
- Convert specific loops to early-continue manually only where the guard style genuinely reads better
- Prefer extracting the loop body into a named method that uses early returns — clearer than either inline form
- grep -r ChangeNestedForeachIfsToEarlyContinueRector across the project to catch shared set files
Example fix
// before (rector.php)
->withRules([
\Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector::class,
])
// code:
foreach ($items as $item) {
if ($item->isValid()) {
if ($item->isReady()) {
$handler->process($item);
}
}
}
// after (rector.php)
// rule removed; loop left as is, or hand-converted where clearer:
foreach ($items as $item) {
if (! $item->isValid()) {
continue;
}
if (! $item->isReady()) {
continue;
}
$handler->process($item);
} Defensive patterns
Strategy: validation
Validate before calling
$deprecated = ['ChangeNestedForeachIfsToEarlyContinueRector'];
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
- Restructure loops manually or by extracting methods with early returns
- Import curated sets instead of enumerating individual style rules
- Delete rules the upgraded Rector version deprecates
- Run vendor/bin/rector dry-run on a fixture path in CI to catch guard throws
When it happens
Trigger: Registering rules/EarlyReturn/Rector/Foreach_/ChangeNestedForeachIfsToEarlyContinueRector.php in config and running rector over any file containing a foreach loop. The throw comes from rules/EarlyReturn/Rector/Foreach_/ChangeNestedForeachIfsToEarlyContinueRector.php:71 on the first Foreach_ node visited.
Common situations: Configs importing the EarlyReturn set or listing this rule individually, carried forward into a Rector version where it was deprecated. The first dry-run over any loop-heavy file (importers, iterators) crashes, which looks like a regression in Rector rather than a config issue.
Related errors
- "%s" rule is deprecated, as it is a personal preference that
- "%s" is deprecated, as match(true) with nested conditions is
- "%s" rule is deprecated, as turning a docblock type into a r
- "%s" rule is deprecated, as risky. The "??" and "?:" operato
- "%s" is deprecated as depends on context and personal prefer
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/2aa6c08c2b12bae1.
Report an issue: GitHub.