Merge pull request #1283 from rectorphp/nette-utils-code-quality-match

[Nette] Add PregFunctionToNetteUtilsStringsRector
This commit is contained in:
Tomáš Votruba 2019-04-02 15:52:27 +02:00 committed by GitHub
commit 0543a5a2ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 474 additions and 10 deletions

View File

@ -41,9 +41,10 @@ Rector **instantly upgrades and instantly refactors PHP code of your application
- Rename classes, methods, properties, namespaces, constants... anything :)
- Add, replace or remove arguments
- Add [parameter or return type declarations](https://www.tomasvotruba.cz/blog/2019/01/03/how-to-complete-type-declarations-without-docblocks-with-rector/) without docblocks - just with static analysis
- Change visibility of constant, property or method
- Upgrade from PHP 5.3 to PHP 7.4
- [Migrate from one PHP framework to another](https://www.tomasvotruba.cz/blog/2019/02/21/how-we-migrated-from-nette-to-symfony-in-3-weeks-part-1/)
- [Complete PHP 7.4 property type declarations](https://www.tomasvotruba.cz/blog/2018/11/15/how-to-get-php-74-typed-properties-to-your-code-in-few-seconds/)
- [Turn Laravel static to Dependency Injection](https://www.tomasvotruba.cz/blog/2019/03/04/how-to-turn-laravel-from-static-to-dependency-injection-in-one-day/)
- And much more...
...**look at overview of [all available Rectors](/docs/AllRectorsOverview.md)** with before/after diffs and configuration examples. You can use them to build your own sets.
@ -323,3 +324,9 @@ Using `rector.yaml`:
```bash
docker run -v $(pwd):/project rector/rector:latest process /project/app --config /project/rector.yaml --autoload-file /project/vendor/autoload.php --dry-run
```
### Community Packages
Do you use Rector to upgrade your code? Share it here:
- [mxr576/drupal8-rector](https://github.com/mxr576/drupal8-rector) by @mxr576

View File

@ -15,3 +15,4 @@ services:
Rector\Nette\Rector\FuncCall\SubstrStrlenFunctionToNetteUtilsStringsRector: ~
Rector\Nette\Rector\Identical\StartsWithFunctionToNetteUtilsStringsRector: ~
Rector\Nette\Rector\Identical\EndsWithFunctionToNetteUtilsStringsRector: ~
Rector\Nette\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector: ~

View File

@ -1,4 +1,4 @@
# All 258 Rectors Overview
# All 263 Rectors Overview
- [Projects](#projects)
- [General](#general)
@ -16,6 +16,7 @@
- [Jms](#jms)
- [Laravel](#laravel)
- [MysqlToMysqli](#mysqltomysqli)
- [Nette](#nette)
- [NetteTesterToPHPUnit](#nettetestertophpunit)
- [NetteToSymfony](#nettetosymfony)
- [PHPStan](#phpstan)
@ -427,7 +428,7 @@ Make if conditions more explicit
public function run($items)
{
- if (!count($items)) {
+ if (count($items) < 0) {
+ if (count($items) !== 0) {
return 'no items';
}
}
@ -1429,6 +1430,113 @@ Replace mysql_pconnect() with mysqli_connect() with host p: prefix
<br>
## Nette
### `SubstrStrlenFunctionToNetteUtilsStringsRector`
- class: `Rector\Nette\Rector\FuncCall\SubstrStrlenFunctionToNetteUtilsStringsRector`
Use Nette\Utils\Strings over bare string-functions
```diff
class SomeClass
{
public function run()
{
- return substr($value, 0, 3);
+ return \Nette\Utils\Strings::substring($value, 0, 3);
}
}
```
<br>
### `PregFunctionToNetteUtilsStringsRector`
- class: `Rector\Nette\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector`
Use Nette\Utils\Strings over bare preg_* functions
```diff
class SomeClass
{
public function run()
{
$content = 'Hi my name is Tom';
- preg_match('#Hi#', $content);
+ \Nette\Utils\Strings::match($content, '#Hi#');
}
}
```
<br>
### `StrposToStringsContainsRector`
- class: `Rector\Nette\Rector\NotIdentical\StrposToStringsContainsRector`
Use Nette\Utils\Strings over bare string-functions
```diff
class SomeClass
{
public function run()
{
$name = 'Hi, my name is Tom';
- return strpos($name, 'Hi') !== false;
+ return \Nette\Utils\Strings::contains($name, 'Hi');
}
}
```
<br>
### `EndsWithFunctionToNetteUtilsStringsRector`
- class: `Rector\Nette\Rector\Identical\EndsWithFunctionToNetteUtilsStringsRector`
Use Nette\Utils\Strings over bare string-functions
```diff
class SomeClass
{
public function end($needle)
{
$content = 'Hi, my name is Tom';
- $yes = substr($content, -strlen($needle)) === $needle;
- $no = $needle !== substr($content, -strlen($needle));
+ $yes = \Nette\Utils\Strings::endsWith($content, $needle);
+ $no = !\Nette\Utils\Strings::endsWith($content, $needle);
}
}
```
<br>
### `StartsWithFunctionToNetteUtilsStringsRector`
- class: `Rector\Nette\Rector\Identical\StartsWithFunctionToNetteUtilsStringsRector`
Use Nette\Utils\Strings over bare string-functions
```diff
class SomeClass
{
public function start($needle)
{
$content = 'Hi, my name is Tom';
- $yes = substr($content, 0, strlen($needle)) === $needle;
- $no = $needle !== substr($content, 0, strlen($needle));
+ $yes = \Nette\Utils\Strings::startwith($content, $needle);
+ $no = !\Nette\Utils\Strings::startwith($content, $needle);
}
}
```
<br>
## NetteTesterToPHPUnit
### `NetteAssertToPHPUnitAssertRector`
@ -2606,7 +2714,7 @@ Changes rand, srand and getrandmax by new md_* alternatives.
- class: `Rector\Php\Rector\FuncCall\PregReplaceEModifierRector`
The /e modifier is no longer supported, use preg_replace_callback instead
The /e modifier is no longer supported, use preg_replace_callback instead
```diff
class SomeClass
@ -3159,7 +3267,7 @@ each() function is deprecated, use foreach() instead.
- class: `Rector\Php\Rector\Each\ListEachRector`
each() function is deprecated, use foreach() instead.
each() function is deprecated, use key() and current() instead
```diff
-list($key, $callback) = each($callbacks);

View File

@ -910,7 +910,7 @@ if (true) {
```php
?>
<strong>feel</strong><?php
<strong>feel</strong><?php
```
<br>

View File

@ -0,0 +1,135 @@
<?php declare(strict_types=1);
namespace Rector\Nette\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see https://www.tomasvotruba.cz/blog/2019/02/07/what-i-learned-by-using-thecodingmachine-safe/#is-there-a-better-way
*/
final class PregFunctionToNetteUtilsStringsRector extends AbstractRector
{
/**
* @var string[]
*/
private $functionNameToMethodName = [
'preg_match' => 'match',
'preg_match_all' => 'matchAll',
'preg_split' => 'split',
'preg_replace' => 'replace',
'preg_replace_callback' => 'replace',
];
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Use Nette\Utils\Strings over bare preg_* functions', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
$content = 'Hi my name is Tom';
preg_match('#Hi#', $content);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
$content = 'Hi my name is Tom';
\Nette\Utils\Strings::match($content, '#Hi#');
}
}
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [FuncCall::class];
}
/**
* @param FuncCall $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isNames($node, array_keys($this->functionNameToMethodName))) {
return null;
}
$methodName = $this->functionNameToMethodName[$this->getName($node)];
$matchStaticCall = $this->createMatchStaticCall($node, $methodName);
// skip assigns, might be used with differnt return value
if ($node->getAttribute(Attribute::PARENT_NODE) instanceof Node\Expr\Assign) {
if ($methodName === 'matchAll') {
// use count
return new FuncCall(new Node\Name('count'), [new Node\Arg($matchStaticCall)]);
}
if ($methodName === 'split') {
return $this->processSplit($node, $matchStaticCall);
}
if ($methodName === 'replace') {
return $matchStaticCall;
}
return null;
}
// assign
if (isset($node->args[2])) {
return new Node\Expr\Assign($node->args[2]->value, $matchStaticCall);
}
return $matchStaticCall;
}
private function createMatchStaticCall(FuncCall $funcCall, string $methodName): Node\Expr\StaticCall
{
$args = [];
if ($methodName === 'replace') {
$args[] = $funcCall->args[2];
$args[] = $funcCall->args[0];
$args[] = $funcCall->args[1];
} else {
$args[] = $funcCall->args[1];
$args[] = $funcCall->args[0];
}
return $this->createStaticCall('Nette\Utils\Strings', $methodName, $args);
}
private function processSplit(FuncCall $funcCall, Node\Expr\StaticCall $matchStaticCall): Node
{
if (isset($funcCall->args[2])) {
if ($this->isValue($funcCall->args[2]->value, -1)) {
if (isset($funcCall->args[3])) {
$matchStaticCall->args[] = $funcCall->args[3];
}
return $matchStaticCall;
}
return $funcCall;
}
return $matchStaticCall;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class SomeClass
{
public function run()
{
$content = 'Hi my name is Tom';
$isIt = preg_match('#Hi#', $content);
if (preg_match('#Hi#', $content)) {
// matched!
}
preg_match('#Hi#', $content, $matches);
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class SomeClass
{
public function run()
{
$content = 'Hi my name is Tom';
$isIt = preg_match('#Hi#', $content);
if (\Nette\Utils\Strings::match($content, '#Hi#')) {
// matched!
}
$matches = \Nette\Utils\Strings::match($content, '#Hi#');
}
}
?>

View File

@ -0,0 +1,43 @@
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregMatchAll
{
public function run()
{
$content = 'Hi my name is Tom, Hi';
$countOfMatches = preg_match_all('#Hi#', $content);
if (preg_match_all('#Hi#', $content)) {
// matched!
}
preg_match_all('#Hi#', $content, $matches);
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregMatchAll
{
public function run()
{
$content = 'Hi my name is Tom, Hi';
$countOfMatches = count(\Nette\Utils\Strings::matchAll($content, '#Hi#'));
if (\Nette\Utils\Strings::matchAll($content, '#Hi#')) {
// matched!
}
$matches = \Nette\Utils\Strings::matchAll($content, '#Hi#');
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregReplace
{
public function run()
{
$content = 'Hi my name is Tom';
$newContent = preg_replace('#Hi#', 'Hello', $content);
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregReplace
{
public function run()
{
$content = 'Hi my name is Tom';
$newContent = \Nette\Utils\Strings::replace($content, '#Hi#', 'Hello');
}
}
?>

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregReplaceCallback
{
public function run()
{
$content = 'Hi my name is Tom';
$newContent = preg_replace_callback('#Hi#', function ($value) {
return 'Hello';
}, $content);
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregReplaceCallback
{
public function run()
{
$content = 'Hi my name is Tom';
$newContent = \Nette\Utils\Strings::replace($content, '#Hi#', function ($value) {
return 'Hello';
});
}
}
?>

View File

@ -0,0 +1,39 @@
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregSplit
{
public function run()
{
$content = 'Hi my name is Tom';
$splitted = preg_split('#Hi#', $content);
$splitted = preg_split('#Hi#', $content, -1);
$splitted = preg_split('#Hi#', $content, -1, PREG_SPLIT_NO_EMPTY);
$splitted = preg_split('#Hi#', $content, 2);
}
}
?>
-----
<?php
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\Fixture;
class PregSplit
{
public function run()
{
$content = 'Hi my name is Tom';
$splitted = \Nette\Utils\Strings::split($content, '#Hi#');
$splitted = \Nette\Utils\Strings::split($content, '#Hi#');
$splitted = \Nette\Utils\Strings::split($content, '#Hi#', PREG_SPLIT_NO_EMPTY);
$splitted = preg_split('#Hi#', $content, 2);
}
}
?>

View File

@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector;
use Rector\Nette\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class PregFunctionToNetteUtilsStringsRectorTest extends AbstractRectorTestCase
{
public function test(): void
{
$this->doTestFiles([
__DIR__ . '/Fixture/preg_match.php.inc',
__DIR__ . '/Fixture/preg_match_all.php.inc',
__DIR__ . '/Fixture/preg_split.php.inc',
__DIR__ . '/Fixture/preg_replace.php.inc',
__DIR__ . '/Fixture/preg_replace_callback.php.inc',
]);
}
protected function getRectorClass(): string
{
return PregFunctionToNetteUtilsStringsRector::class;
}
}

View File

@ -9,10 +9,7 @@ final class ActionSuffixRemoverRectorTest extends AbstractRectorTestCase
{
public function test(): void
{
$this->doTestFiles([
// __DIR__ . '/Fixture/fixture.php.inc',
__DIR__ . '/Fixture/fixture2.php.inc',
]);
$this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc', __DIR__ . '/Fixture/fixture2.php.inc']);
}
public function getRectorClass(): string