Skip to content

Add new Rector rules and improve compatibility#6

Merged
spawnia merged 8 commits intomasterfrom
if-throw-to-coalesce-throw-rector
Jan 20, 2026
Merged

Add new Rector rules and improve compatibility#6
spawnia merged 8 commits intomasterfrom
if-throw-to-coalesce-throw-rector

Conversation

@spawnia
Copy link
Copy Markdown
Member

@spawnia spawnia commented Jan 16, 2026

Summary

  • Add IfThrowToCoalesceThrowRector to transform null-check-then-throw patterns to use the null coalesce operator with throw expression
  • Add ElvisToCoalesceRector to convert elvis operator (?:) to null coalesce (??) when the expression can only be falsy via null
  • Select FirstClassCallableRector or ArrayToFirstClassCallableRector based on Rector version
  • Fix Rector 1.x compatibility for IfThrowToCoalesceThrowRector

Example

Before:

$value = getValue();
if ($value === null) {
    throw new Exception('Value required');
}

$foo = $bar ?: 'default';

After:

$value = getValue() ?? throw new Exception('Value required');

$foo = $bar ?? 'default';

Test plan

  • PHPStan passes
  • Tests pass

🤖 Generated with Claude Code

spawnia and others added 2 commits January 16, 2026 17:24
Transform patterns like:

    $value = getValue();
    if ($value === null) {
        throw new Exception();
    }

Into:

    $value = getValue() ?? throw new Exception();

Also supports the elvis operator pattern for falsy checks.

Co-Authored-By: Claude <noreply@anthropic.com>
- Use `ClassMethod::class` and `Function_::class` instead of `NodeGroup::STMTS_AWARE`
  which only exists in Rector 2.x
- Handle `Stmt\Throw_` (traditional throw statement) in addition to
  `Expr\Throw_` (PHP 8.0+ throw expression) for AST compatibility
- Use `FirstClassCallableRector` in config.php which works in both versions

Co-Authored-By: Claude <noreply@anthropic.com>
@spawnia
Copy link
Copy Markdown
Member Author

spawnia commented Jan 16, 2026

Formatting will be handled by mll-lab/php-cs-fixer-config#14.

spawnia and others added 2 commits January 16, 2026 20:58
In Rector 2.x, FirstClassCallableRector is deprecated and replaced by
ArrayToFirstClassCallableRector. Use class_exists() to conditionally
select the correct class based on the installed Rector version.

Co-Authored-By: Claude <noreply@anthropic.com>
@spawnia spawnia requested a review from simbig January 16, 2026 20:48
@spawnia spawnia marked this pull request as ready for review January 16, 2026 21:09
- Add ElvisToCoalesceRector: converts ?: to ?? when expression type can
  only be falsy via null (e.g., object|null)
- Extract shared isOnlyNullFalsy() logic into NullFalsyTypeTrait
- IfThrowToCoalesceThrowRector now prefers ?? over ?: when type analysis
  shows null is the only possible falsy value

Co-Authored-By: Claude <noreply@anthropic.com>
@spawnia
Copy link
Copy Markdown
Member Author

spawnia commented Jan 20, 2026

Added ElvisToCoalesceRector which converts ?: to ?? when the expression type can only be falsy via null (e.g., ?\stdClass).

Also improved IfThrowToCoalesceThrowRector to prefer ?? over ?: when type analysis shows this is safe. The shared type-checking logic is extracted into NullFalsyTypeTrait.

@simbig could you re-review?

@spawnia spawnia changed the title Add IfThrowToCoalesceThrowRector Add new Rector rules and improve compatibility Jan 20, 2026
Change getNativeType() to getType() so docblock types are considered,
not just native PHP type declarations.

Co-Authored-By: Claude <noreply@anthropic.com>
@spawnia spawnia merged commit 8b9e885 into master Jan 20, 2026
12 checks passed
@spawnia spawnia deleted the if-throw-to-coalesce-throw-rector branch January 20, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants