mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-14 12:29:43 +01:00
[PHP 8] Add str_ends_with
This commit is contained in:
parent
62ca1f270c
commit
833435037a
@ -2,3 +2,4 @@ services:
|
||||
Rector\Php80\Rector\FunctionLike\UnionTypesRector: null
|
||||
Rector\Php80\Rector\NotIdentical\StrContainsRector: null
|
||||
Rector\Php80\Rector\Identical\StrStartsWithRector: null
|
||||
Rector\Php80\Rector\Identical\StrEndsWithRector: null
|
||||
|
@ -1,4 +1,4 @@
|
||||
# All 500 Rectors Overview
|
||||
# All 501 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
- [General](#general)
|
||||
@ -7872,6 +7872,26 @@ Replace strpos() !== false and strstr() with str_contains()
|
||||
|
||||
<br>
|
||||
|
||||
### `StrEndsWithRector`
|
||||
|
||||
- class: [`Rector\Php80\Rector\Identical\StrEndsWithRector`](/../master/rules/php80/src/Rector/Identical/StrEndsWithRector.php)
|
||||
- [test fixtures](/../master/rules/php80/tests/Rector/Identical/StrEndsWithRector/Fixture)
|
||||
|
||||
Change helper functions to str_ends_with()
|
||||
|
||||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
- $isMatch = substr($haystack, -strlen($needle)) === $needle;
|
||||
+ $isMatch = str_ends_with($haystack, $needle);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### `StrStartsWithRector`
|
||||
|
||||
- class: [`Rector\Php80\Rector\Identical\StrStartsWithRector`](/../master/rules/php80/src/Rector/Identical/StrStartsWithRector.php)
|
||||
|
137
rules/php80/src/Rector/Identical/StrEndsWithRector.php
Normal file
137
rules/php80/src/Rector/Identical/StrEndsWithRector.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php80\Rector\Identical;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\BinaryOp;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\UnaryMinus;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
|
||||
*
|
||||
* @see \Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\StrEndsWithRectorTest
|
||||
*/
|
||||
final class StrEndsWithRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change helper functions to str_ends_with()', [
|
||||
new CodeSample(
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = substr($haystack, -strlen($needle)) === $needle;
|
||||
}
|
||||
}
|
||||
PHP
|
||||
,
|
||||
<<<'PHP'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = str_ends_with($haystack, $needle);
|
||||
}
|
||||
}
|
||||
PHP
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Identical::class, NotIdentical::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Identical|NotIdentical $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
return $this->refactorSubstr($node) ?? $this->refactorSubstrCompare($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Covers:
|
||||
* $isMatch = substr($haystack, -strlen($needle)) === $needle;
|
||||
*/
|
||||
private function refactorSubstr(BinaryOp $binaryOp): ?FuncCall
|
||||
{
|
||||
if ($this->isFuncCallName($binaryOp->left, 'substr')) {
|
||||
$substrFuncCall = $binaryOp->left;
|
||||
$comparedNeedleExpr = $binaryOp->right;
|
||||
} elseif ($this->isFuncCallName($binaryOp->right, 'substr')) {
|
||||
$substrFuncCall = $binaryOp->right;
|
||||
$comparedNeedleExpr = $binaryOp->left;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$haystack = $substrFuncCall->args[0]->value;
|
||||
|
||||
$needle = $this->matchUnaryMinusStrlenFuncCallArgValue($substrFuncCall->args[1]->value);
|
||||
if (! $this->areNodesEqual($needle, $comparedNeedleExpr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->createFuncCall('str_ends_with', [$haystack, $needle]);
|
||||
}
|
||||
|
||||
private function refactorSubstrCompare(BinaryOp $binaryOp): ?FuncCall
|
||||
{
|
||||
if ($this->isFuncCallName($binaryOp->left, 'substr_compare')) {
|
||||
$substrCompareFuncCall = $binaryOp->left;
|
||||
if (! $this->isValue($binaryOp->right, 0)) {
|
||||
return null;
|
||||
}
|
||||
} elseif ($this->isFuncCallName($binaryOp->right, 'substr_compare')) {
|
||||
$substrCompareFuncCall = $binaryOp->right;
|
||||
if (! $this->isValue($binaryOp->left, 0)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$haystack = $substrCompareFuncCall->args[0]->value;
|
||||
$needle = $substrCompareFuncCall->args[1]->value;
|
||||
|
||||
$comparedNeedleExpr = $this->matchUnaryMinusStrlenFuncCallArgValue($substrCompareFuncCall->args[2]->value);
|
||||
if (! $this->areNodesEqual($needle, $comparedNeedleExpr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->createFuncCall('str_ends_with', [$haystack, $needle]);
|
||||
}
|
||||
|
||||
private function matchUnaryMinusStrlenFuncCallArgValue(Node $node): ?Expr
|
||||
{
|
||||
if (! $node instanceof UnaryMinus) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isFuncCallName($node->expr, 'strlen')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var FuncCall $funcCall */
|
||||
$funcCall = $node->expr;
|
||||
|
||||
return $funcCall->args[0]->value;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = substr($haystack, -strlen($needle)) === $needle;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = str_ends_with($haystack, $needle);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SkipSubstrCompareNotZero
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = substr_compare($haystack, $needle, -strlen($needle)) === 3;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SubstrCompare
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = substr_compare($haystack, $needle, -strlen($needle)) === 0;
|
||||
|
||||
$isMatch = 0 === substr_compare($haystack, $needle, -strlen($needle));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SubstrCompare
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = str_ends_with($haystack, $needle);
|
||||
|
||||
$isMatch = str_ends_with($haystack, $needle);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SubstrOtherWay
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = $needle === substr($haystack, -strlen($needle));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector\Fixture;
|
||||
|
||||
class SubstrOtherWay
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$isMatch = str_ends_with($haystack, $needle);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\Identical\StrEndsWithRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\Php80\Rector\Identical\StrEndsWithRector;
|
||||
|
||||
final class StrEndsWithRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return StrEndsWithRector::class;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user