diff --git a/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/is_null_function.php.inc b/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/is_null_function.php.inc new file mode 100644 index 00000000000..9e5a19156e2 --- /dev/null +++ b/rules-tests/Php70/Rector/Ternary/TernaryToNullCoalescingRector/Fixture/is_null_function.php.inc @@ -0,0 +1,33 @@ + +----- + diff --git a/rules/Php70/Rector/Ternary/TernaryToNullCoalescingRector.php b/rules/Php70/Rector/Ternary/TernaryToNullCoalescingRector.php index 5ff9d513d0a..c18d1e78c5d 100644 --- a/rules/Php70/Rector/Ternary/TernaryToNullCoalescingRector.php +++ b/rules/Php70/Rector/Ternary/TernaryToNullCoalescingRector.php @@ -9,6 +9,8 @@ use PhpParser\Node\Expr\BinaryOp\Coalesce; use PhpParser\Node\Expr\BinaryOp\Identical; use PhpParser\Node\Expr\BinaryOp\NotIdentical; +use PhpParser\Node\Expr\BooleanNot; +use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\Isset_; use PhpParser\Node\Expr\Ternary; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -37,6 +39,7 @@ public function getRuleDefinition(): RuleDefinition [ new CodeSample('$value === null ? 10 : $value;', '$value ?? 10;'), new CodeSample('isset($value) ? $value : 10;', '$value ?? 10;'), + new CodeSample('is_null($value) ? 10 : $value;', '$value ?? 10;'), ] ); } @@ -58,6 +61,17 @@ public function refactor(Node $node): ?Node return $this->processTernaryWithIsset($node, $node->cond); } + if ($node->cond instanceof FuncCall && $this->isName($node->cond, 'is_null')) { + return $this->processTernaryWithIsNull($node, $node->cond, false); + } + + if ( + $node->cond instanceof BooleanNot && $node->cond->expr instanceof FuncCall + && $this->isName($node->cond->expr, 'is_null') + ) { + return $this->processTernaryWithIsNull($node, $node->cond->expr, true); + } + if ($node->cond instanceof Identical) { $checkedNode = $node->else; $fallbackNode = $node->if; @@ -95,6 +109,42 @@ public function provideMinPhpVersion(): int return PhpVersionFeature::NULL_COALESCE; } + private function processTernaryWithIsNull(Ternary $ternary, FuncCall $isNullFuncCall, bool $isNegated): ?Coalesce + { + if (count($isNullFuncCall->args) !== 1) { + return null; + } + + $firstArg = $isNullFuncCall->args[0]; + if (! $firstArg instanceof Node\Arg) { + return null; + } + + $checkedExpr = $firstArg->value; + + if ($isNegated) { + if (! $ternary->if instanceof Expr) { + return null; + } + + if (! $this->nodeComparator->areNodesEqual($ternary->if, $checkedExpr)) { + return null; + } + + return new Coalesce($ternary->if, $ternary->else); + } + + if (! $this->nodeComparator->areNodesEqual($ternary->else, $checkedExpr)) { + return null; + } + + if (! $ternary->if instanceof Expr) { + return null; + } + + return new Coalesce($ternary->else, $ternary->if); + } + private function processTernaryWithIsset(Ternary $ternary, Isset_ $isset): ?Coalesce { if (! $ternary->if instanceof Expr) {