rectorphp/rector · error · ShouldNotHappenException

"%s" rule is deprecated, as a function call can rarely be tu

Error message

"%s" rule is deprecated, as a function call can rarely be turned to a method call without breaking the code; use a custom rule for the exact project case instead

What it means

Rector\Transform\Rector\FuncCall\FuncCallToMethodCallRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first Class_ node. The rule turned configured global function calls (e.g. some_helper()) into static or service method calls, but a function call can rarely be swapped for a method call without breaking code - the target object may not exist, names collide, and call semantics differ. configure() is a no-op now, so previously passed mappings are ignored.

Source

Thrown at rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php:64

        $this->someRenderer->view('...');
    }
}
CODE_SAMPLE
, [new FuncCallToMethodCall('view', 'Namespaced\SomeRenderer', 'render')])]);
    }
    /**
     * @return array<class-string<Node>>
     */
    public function getNodeTypes(): array
    {
        return [Class_::class];
    }
    /**
     * @param Class_ $node
     */
    public function refactor(Node $node): ?Node
    {
        throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as a function call can rarely be turned to a method call without breaking the code; use a custom rule for the exact project case instead', self::class));
    }
    /**
     * @param mixed[] $configuration
     */
    public function configure(array $configuration): void
    {
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove FuncCallToMethodCallRector from rector.php.
  2. Do the function-to-method migration by hand per call site, verifying the receiver object is actually available there.
  3. If it is a standing project convention, write a custom rule scoped to the exact function/method pair.

Example fix

// before (rector.php)
->withConfiguredRule(FuncCallToMethodCallRector::class, [
    'some_helper' => [SomeService::class, 'helper'],
])

// after (rector.php) - removed; migrate call sites by hand

// before                 // after
$value = some_helper();    $value = $this->someService->helper();
Defensive patterns

Strategy: validation

Validate before calling

use Rector\Transform\Rector\FuncCall\FuncCallToMethodCallRector;

$rules = [/* your list */ FuncCallToMethodCallRector::class];
if (in_array(FuncCallToMethodCallRector::class, $rules, true)) {
    throw new InvalidArgumentException('Rule deprecated; migrate function calls manually or via a custom project rule');
}

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'FuncCallToMethodCallRector')) {
        fwrite(STDERR, 'Remove the rule; function-to-method swaps need per-call-site verification.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule remains in rector.php (withRules() or withConfiguredRule() with an old function=>method map) and rector visits any class; refactor() throws on the first Class_ node.

Common situations: Old configs migrating helper functions to a service class; projects that wired e.g. env() or trans() helpers to method calls; CI failing after a rector upgrade that emptied the implementation.

Related errors


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