diff --git a/README.md b/README.md index 7b6446553822..bf909785813b 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ Rector **instantly upgrades and instantly refactors PHP code of your application composer require rector/rector --dev ``` -**Do you have conflicts on `composer require`?** +**Do you have conflicts on `composer require` or on run?** -Install [prefixed version](https://github.com/rectorphp/rector-prefixed) with isolated dependencies. +- use [Docker image](#run-rector-in-docker) or +- install [prefixed version](https://github.com/rectorphp/rector-prefixed) with isolated dependencies (currently [looking for maintainer](https://github.com/rectorphp/prefixer/issues/1)) ### Extra Autoloading @@ -163,8 +164,10 @@ Just follow 3 rules: We would be happy to merge your feature then. -## Run rector in docker +## Run Rector in Docker + With this command, you can process your project with rector from docker: + ```bash docker run -v $(pwd):/project rector/rector:latest ``` diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index e06a3447ee2f..85af4060d7d2 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -47,8 +47,10 @@ - [Php\Each](#phpeach) - [Php\FuncCall](#phpfunccall) - [Php\FunctionLike](#phpfunctionlike) +- [Php\If_](#phpif_) - [Php\List_](#phplist_) - [Php\MagicConstClass](#phpmagicconstclass) +- [Php\MethodCall](#phpmethodcall) - [Php\Name](#phpname) - [Php\Property](#phpproperty) - [Php\StaticCall](#phpstaticcall) @@ -1488,7 +1490,7 @@ Changes unquoted non-existing constants to strings ```diff -var_dump(VAR); -+var("VAR"); ++var_dump("VAR"); ```
@@ -1605,7 +1607,7 @@ Null is no more allowed in get_class() - class: `Rector\Php\Rector\FuncCall\TrailingCommaArgumentsRector` -Adds trailing commas to function and methods calls +Adds trailing commas to function and methods calls ```diff calling( @@ -1983,6 +1985,33 @@ Changes PHP 4 style constructor to __construct.
+## Php\If_ + +### `IfToSpaceshipRector` + +- class: `Rector\Php\Rector\If_\IfToSpaceshipRector` + +Changes if/else to spaceship <=> where useful + +```diff + class SomeClass + { + public function run() + { + usort($languages, function ($a, $b) { +- if ($a[0] === $b[0]) { +- return 0; +- } +- +- return ($a[0] < $b[0]) ? 1 : -1; ++ return $b[0] <=> $a[0]; + }); + } + } +``` + +
+ ## Php\List_ ### `ListSplitStringRector` @@ -2045,6 +2074,58 @@ Change __CLASS__ to self::class
+## Php\MethodCall + +### `ThisCallOnStaticMethodToStaticCallRector` + +- class: `Rector\Php\Rector\MethodCall\ThisCallOnStaticMethodToStaticCallRector` + +Changes $this->call() to static method to static call + +```diff + class SomeClass + { + public static function run() + { +- $this->eat(); ++ self::eat(); + } + + public static function eat() + { + } + } +``` + +
+ +### `PreferThisOrSelfMethodCallRector` + +- class: `Rector\Php\Rector\MethodCall\PreferThisOrSelfMethodCallRector` + +Changes $this->... to self:: or vise versa for specific types + +```yaml +services: + Rector\Php\Rector\MethodCall\PreferThisOrSelfMethodCallRector: + PHPUnit\TestCase: self +``` + +↓ + +```diff + class SomeClass extends PHPUnit\TestCase + { + public function run() + { +- $this->assertThis(); ++ self::assertThis(); + } + } +``` + +
+ ## Php\Name ### `ReservedObjectRector` @@ -2108,6 +2189,32 @@ Changes property `@var` annotations from annotation to type. ## Php\StaticCall +### `StaticCallOnNonStaticToInstanceCallRector` + +- class: `Rector\Php\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector` + +Changes static call to instance call, where not useful + +```diff + class Something + { + public function doWork() + { + } + } + + class Another + { + public function run() + { +- return Something::doWork(); ++ return (new Something)->doWork(); + } + } +``` + +
+ ### `ExportToReflectionFunctionRector` - class: `Rector\Php\Rector\StaticCall\ExportToReflectionFunctionRector` diff --git a/packages/Php/src/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php b/packages/Php/src/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php new file mode 100644 index 000000000000..9e44e380f704 --- /dev/null +++ b/packages/Php/src/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php @@ -0,0 +1,151 @@ +typeToPreference = $typeToPreference; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Changes $this->... to self:: or vise versa for specific types', [ + new ConfiguredCodeSample( + <<<'CODE_SAMPLE' +class SomeClass extends PHPUnit\TestCase +{ + public function run() + { + $this->assertThis(); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass extends PHPUnit\TestCase +{ + public function run() + { + self::assertThis(); + } +} +CODE_SAMPLE + , + ['PHPUnit\TestCase' => self::PREFER_SELF] + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [MethodCall::class, StaticCall::class]; + } + + /** + * @param MethodCall|StaticCall $node + */ + public function refactor(Node $node): ?Node + { + foreach ($this->typeToPreference as $type => $preference) { + if (! $this->isType($node, $type)) { + continue; + } + + $this->ensurePreferceIsValid($preference); + + if ($preference === self::PREFER_SELF) { + return $this->processToSelf($node); + } + + if ($preference === self::PREFER_THIS) { + return $this->processToThis($node); + } + } + + return $node; + } + + /** + * @param MethodCall|StaticCall $node + */ + private function processToSelf(Node $node): ?StaticCall + { + if ($node instanceof StaticCall) { + return null; + } + + if (! $this->isName($node->var, 'this')) { + return null; + } + + return new StaticCall(new Name('self'), $node->name); + } + + /** + * @param MethodCall|StaticCall $node + */ + private function processToThis(Node $node): ?MethodCall + { + if ($node instanceof MethodCall) { + return null; + } + + if (! $this->isName($node->class, 'self')) { + return null; + } + + return new MethodCall(new Variable('this'), $node->name); + } + + /** + * @param mixed $preference + */ + private function ensurePreferceIsValid($preference): void + { + $allowedPreferences = [self::PREFER_THIS, self::PREFER_SELF]; + if (in_array($preference, $allowedPreferences, true)) { + return; + } + + throw new InvalidRectorConfigurationException(sprintf( + 'Preference configuration "%s" for "%s" is not valid. Use one of "%s"', + $preference, + self::class, + implode('", "', $allowedPreferences) + )); + } +} diff --git a/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_self.php.inc b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_self.php.inc new file mode 100644 index 000000000000..d8107ae08cff --- /dev/null +++ b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_self.php.inc @@ -0,0 +1,35 @@ +assertThis(); + self::assertThis(); + parent::assertThis(); + } +} + +?> +----- + diff --git a/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_this.php.inc b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_this.php.inc new file mode 100644 index 000000000000..4968c2f2f9a0 --- /dev/null +++ b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Fixture/to_this.php.inc @@ -0,0 +1,35 @@ +assertThis(); + self::assertThis(); + parent::assertThis(); + } +} + +?> +----- +assertThis(); + $this->assertThis(); + parent::assertThis(); + } +} + +?> diff --git a/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/PreferThisOrSelfMethodCallRectorTest.php b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/PreferThisOrSelfMethodCallRectorTest.php new file mode 100644 index 000000000000..eac43bb2e0f1 --- /dev/null +++ b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/PreferThisOrSelfMethodCallRectorTest.php @@ -0,0 +1,32 @@ +doTestFiles([__DIR__ . '/Fixture/to_self.php.inc', __DIR__ . '/Fixture/to_this.php.inc']); + } + + protected function getRectorClass(): string + { + return PreferThisOrSelfMethodCallRector::class; + } + + /** + * @return mixed[] + */ + protected function getRectorConfiguration(): array + { + return [ + AbstractTestCase::class => 'self', + BeLocalClass::class => 'this', + ]; + } +} diff --git a/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Source/AbstractTestCase.php b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Source/AbstractTestCase.php new file mode 100644 index 000000000000..26d3cbd5f334 --- /dev/null +++ b/packages/Php/tests/Rector/MethodCall/PreferThisOrSelfMethodCallRector/Source/AbstractTestCase.php @@ -0,0 +1,8 @@ +