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

  1. Remove EncapsedStringsToSprintfRector::class from rector.php / imported sets and re-run dry-run
  2. If your translation pipeline genuinely needs sprintf(), convert the translatable strings manually or scope a custom rule to that one directory
  3. Keep normal strings interpolated — it is the clearer, idiomatic form
  4. 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

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


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