rectorphp/rector · error · ShouldNotHappenException

"%s" rule is deprecated, as property hooks are a matter of p

Error message

"%s" rule is deprecated, as property hooks are a matter of preference. They provide no upgrade value and make the code harder to read

What it means

Rector\Php84\Rector\Class_\PropertyHookRector is deprecated: refactor() throws Rector\Exception\ShouldNotHappenException on the first Class_ node. The rule rewrote getter/setter method pairs into PHP 8.4 property hooks, but hooks are a stylistic preference with no upgrade value, and the mechanical rewrite often made classes harder to read. The rule requires PhpVersionFeature::PROPERTY_HOOKS, so it only loads on PHP 8.4+ targets.

Source

Thrown at rules/Php84/Rector/Class_/PropertyHookRector.php:60

    {
        get => $this->name;
        set($value) => $this->name = ucfirst($value);
    }
}

CODE_SAMPLE
)]);
    }
    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 property hooks are a matter of preference. They provide no upgrade value and make the code harder to read', self::class));
    }
    public function provideMinPhpVersion(): int
    {
        return PhpVersionFeature::PROPERTY_HOOKS;
    }
}

View on GitHub (pinned to 408fcb0ff1)

Solutions

  1. Remove PropertyHookRector from rector.php; property hooks are opt-in style, not an upgrade step.
  2. If the team genuinely prefers hooks, convert specific getter/setter pairs by hand and review each diff in code review.
  3. Do not try to keep the rule via an older rector pin - it is intentionally gone.

Example fix

// before (rector.php)
->withRules([PropertyHookRector::class])

// after (rector.php) - removed; convert by hand where wanted

// manual, opt-in per case (PHP 8.4):
public string $name {
    set => trim($value);
}
Defensive patterns

Strategy: validation

Validate before calling

use Rector\Php84\Rector\Class_\PropertyHookRector;

$rules = [/* your list */ PropertyHookRector::class];
if (in_array(PropertyHookRector::class, $rules, true)) {
    throw new InvalidArgumentException('PropertyHookRector is deprecated; property hooks are opt-in style, not an upgrade');
}

Try / catch

try {
    exit($rectorApplication->run());
} catch (\Rector\Exception\ShouldNotHappenException $e) {
    if (str_contains($e->getMessage(), 'PropertyHookRector')) {
        fwrite(STDERR, 'Remove the rule; convert getter/setter pairs to hooks manually where the team wants them.' . PHP_EOL);
        exit(1);
    }
    throw $e;
}

Prevention

When it happens

Trigger: The rule is still listed in a withPhp84()-style custom rule list or withRules() and rector visits any class declaration; refactor() throws immediately on the first Class_ node.

Common situations: Adopting a PHP 8.4 upgrade config copied from an older template; CI breaking after a rector upgrade that gutted the rule; teams that enabled it 'to try hooks' and forgot it in the config.

Related errors


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