Merge pull request #3245 from rectorphp/strinable

This commit is contained in:
Tomas Votruba 2020-04-24 14:10:38 +02:00 committed by GitHub
commit 40275b2766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 179 additions and 1 deletions

View File

@ -3,3 +3,4 @@ services:
Rector\Php80\Rector\NotIdentical\StrContainsRector: null
Rector\Php80\Rector\Identical\StrStartsWithRector: null
Rector\Php80\Rector\Identical\StrEndsWithRector: null
Rector\Php80\Rector\Class_\StringableForToStringRector: null

View File

@ -1,4 +1,4 @@
# All 501 Rectors Overview
# All 502 Rectors Overview
- [Projects](#projects)
- [General](#general)
@ -7915,6 +7915,27 @@ Change helper functions to str_starts_with()
<br>
### `StringableForToStringRector`
- class: [`Rector\Php80\Rector\Class_\StringableForToStringRector`](/../master/rules/php80/src/Rector/Class_/StringableForToStringRector.php)
- [test fixtures](/../master/rules/php80/tests/Rector/Class_/StringableForToStringRector/Fixture)
Add `Stringable` interface to classes with `__toString()` method
```diff
-class SomeClass
+class SomeClass implements Stringable
{
- public function __toString()
+ public function __toString(): string
{
return 'I can stringz';
}
}
```
<br>
### `UnionTypesRector`
- class: [`Rector\Php80\Rector\FunctionLike\UnionTypesRector`](/../master/rules/php80/src/Rector/FunctionLike/UnionTypesRector.php)

View File

@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace Rector\Php80\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\PhpParser\Node\Manipulator\ClassManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
/**
* @see https://wiki.php.net/rfc/stringable
*
* @see \Rector\Php80\Tests\Rector\Class_\StringableForToStringRector\StringableForToStringRectorTest
*/
final class StringableForToStringRector extends AbstractRector
{
/**
* @var string
*/
private const STRINGABLE = 'Stringable';
/**
* @var ClassManipulator
*/
private $classManipulator;
public function __construct(ClassManipulator $classManipulator)
{
$this->classManipulator = $classManipulator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Add `Stringable` interface to classes with `__toString()` method', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public function __toString()
{
return 'I can stringz';
}
}
PHP
,
<<<'PHP'
class SomeClass implements Stringable
{
public function __toString(): string
{
return 'I can stringz';
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$toStringClassMethod = $node->getMethod('__toString');
if ($toStringClassMethod === null) {
return null;
}
if ($this->classManipulator->hasInterface($node, self::STRINGABLE)) {
return null;
}
// add interface
$node->implements[] = new FullyQualified(self::STRINGABLE);
// add return type
if ($toStringClassMethod->returnType === null) {
$toStringClassMethod->returnType = new Name('string');
}
return $node;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Rector\Php80\Tests\Rector\Class_\StringableForToStringRector\Fixture;
class SomeClass
{
public function __toString()
{
return 'I can stringz';
}
}
?>
-----
<?php
namespace Rector\Php80\Tests\Rector\Class_\StringableForToStringRector\Fixture;
class SomeClass implements \Stringable
{
public function __toString(): string
{
return 'I can stringz';
}
}
?>

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Rector\Php80\Tests\Rector\Class_\StringableForToStringRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Php80\Rector\Class_\StringableForToStringRector;
final class StringableForToStringRectorTest 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 StringableForToStringRector::class;
}
}