rectorphp/rector · error · ShouldNotHappenException
"%s" is deprecated, as converting string interpolation to sp
Error message
"%s" is deprecated, as converting string interpolation to sprintf() is a personal preference that can worsen readability
What it means
EncapsedStringsToSprintfRector used to rewrite interpolated strings like "Hello $name, you are $age" into sprintf('Hello %s, you are %d', $name, $age). It is deprecated because that conversion is a personal preference that often worsens readability — interpolation is the idiomatic PHP style. refactor() now throws ShouldNotHappenException on every InterpolatedString node; the rule performs no rewrite and serves only to abort stale configurations.
Source
Thrown at rules/CodingStyle/Rector/Encapsed/EncapsedStringsToSprintfRector.php:56
echo sprintf('Unsupported format %s - use another', $format);
echo 'Try ' . $allowed;
CODE_SAMPLE
, [self::ALWAYS => \false])]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [InterpolatedString::class];
}
/**
* @param InterpolatedString $node
*/
public function refactor(Node $node): ?Node
{
throw new ShouldNotHappenException(sprintf('"%s" is deprecated, as converting string interpolation to sprintf() is a personal preference that can worsen readability', self::class));
}
}
View on GitHub (pinned to 408fcb0ff1)
Solutions
- Remove EncapsedStringsToSprintfRector::class from rector.php / imported sets and re-run dry-run
- If your translation pipeline genuinely needs sprintf(), convert the translatable strings manually or scope a custom rule to that one directory
- Keep normal strings interpolated — it is the clearer, idiomatic form
- Check shared set bundles your config imports for lingering references
Example fix
// before (rector.php)
->withRules([
\Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector::class,
]);
// code:
$message = "Hello $name, you are $age";
// after (rector.php)
// rule removed
// code kept as interpolation; convert by hand only where tools require it:
$message = sprintf('Hello %s, you are %d', $name, $age); Defensive patterns
Strategy: validation
Validate before calling
$deprecated = ['EncapsedStringsToSprintfRector'];
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
- Keep user-facing strings interpolated; convert to sprintf() only where tooling (translation extractors) needs it
- Scope any sprintf conversion to the specific directory via a custom rule or manual pass
- Prune deprecated rules during each Rector upgrade
- Dry-run in CI on representative files to catch guard throws
When it happens
Trigger: Registering rules/CodingStyle/Rector/Encapsed/EncapsedStringsToSprintfRector.php in config and running rector over any file containing a double-quoted string with variables. The throw fires at rules/CodingStyle/Rector/Encapsed/EncapsedStringsToSprintfRector.php:56 on the first interpolated string.
Common situations: Configs that adopted this rule for translation-tooling workflows (some translation extractors prefer sprintf) still reference it after a Rector upgrade. Because interpolated strings are everywhere, the exception appears on the first analysed file and looks like an internal Rector failure rather than a config issue.
Related errors
- "%s" rule is deprecated, as it is a coding standard preferen
- "%s" is deprecated as depends on context and personal prefer
- "%s" rule is deprecated, as it is a personal preference that
- "%s" is deprecated, as simplifying regex ranges is a persona
- "%s" rule is deprecated, as it is a personal preference that
AI-assisted analysis of rectorphp/rector@408fcb0ff1 (2026-08-21).
Data as JSON: /api/errors/cbea45e1628ebe57.
Report an issue: GitHub.