Deprecate RemovingStatic rules as very narrow use case in generic rules (#1819)

This commit is contained in:
Tomas Votruba 2022-02-15 22:38:07 +00:00 committed by GitHub
parent 9fe44263f9
commit 92d04a5547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 29 additions and 1085 deletions

View File

@ -1,4 +1,4 @@
# 524 Rules Overview
# 520 Rules Overview
<br>
@ -8,7 +8,7 @@
- [Autodiscovery](#autodiscovery) (4)
- [CodeQuality](#codequality) (70)
- [CodeQuality](#codequality) (71)
- [CodingStyle](#codingstyle) (35)
@ -76,7 +76,7 @@
- [Php74](#php74) (15)
- [Php80](#php80) (18)
- [Php80](#php80) (17)
- [Php81](#php81) (9)
@ -88,7 +88,7 @@
- [Removing](#removing) (6)
- [RemovingStatic](#removingstatic) (5)
- [RemovingStatic](#removingstatic) (1)
- [Renaming](#renaming) (11)
@ -1127,6 +1127,24 @@ Change unsafe new `static()` to new `self()`
<br>
### OptionalParametersAfterRequiredRector
Move required parameters after optional ones
- class: [`Rector\CodeQuality\Rector\ClassMethod\OptionalParametersAfterRequiredRector`](../rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php)
```diff
class SomeObject
{
- public function run($optional = 1, $required)
+ public function run($required, $optional = 1)
{
}
}
```
<br>
### RemoveAlwaysTrueConditionSetInConstructorRector
If conditions is always true, perform the content right away
@ -8350,24 +8368,6 @@ Change ternary type resolve to `get_debug_type()`
<br>
### OptionalParametersAfterRequiredRector
Move required parameters after optional ones
- class: [`Rector\Php80\Rector\ClassMethod\OptionalParametersAfterRequiredRector`](../rules/Php80/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php)
```diff
class SomeObject
{
- public function run($optional = 1, $required)
+ public function run($required, $optional = 1)
{
}
}
```
<br>
### Php8ResourceReturnToObjectRector
Change `is_resource()` to instanceof Object
@ -9566,108 +9566,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
## RemovingStatic
### DesiredClassTypeToDynamicRector
Change full static service, to dynamic one
- class: [`Rector\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector`](../rules/RemovingStatic/Rector/Class_/DesiredClassTypeToDynamicRector.php)
```diff
class AnotherClass
{
+ /**
+ * @var SomeClass
+ */
+ private $someClass;
+
+ public fuction __construct(SomeClass $someClass)
+ {
+ $this->someClass = $someClass;
+ }
+
public function run()
{
SomeClass::someStatic();
}
}
class SomeClass
{
- public static function run()
+ public function run()
{
- self::someStatic();
+ $this->someStatic();
}
- private static function someStatic()
+ private function someStatic()
{
}
}
```
<br>
### DesiredPropertyClassMethodTypeToDynamicRector
Change defined static properties and methods to dynamic
- class: [`Rector\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector`](../rules/RemovingStatic/Rector/Property/DesiredPropertyClassMethodTypeToDynamicRector.php)
```diff
final class SomeClass
{
- public static $name;
+ public $name;
- public static function go()
+ public function go()
{
}
}
```
<br>
### DesiredStaticCallTypeToDynamicRector
Change defined static service to dynamic one
- class: [`Rector\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector`](../rules/RemovingStatic/Rector/StaticCall/DesiredStaticCallTypeToDynamicRector.php)
```diff
final class SomeClass
{
public function run()
{
- SomeStaticMethod::someStatic();
+ $this->someStaticMethod->someStatic();
}
}
```
<br>
### DesiredStaticPropertyFetchTypeToDynamicRector
Change defined static service to dynamic one
- class: [`Rector\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector`](../rules/RemovingStatic/Rector/StaticPropertyFetch/DesiredStaticPropertyFetchTypeToDynamicRector.php)
```diff
final class SomeClass
{
public function run()
{
- SomeStaticMethod::$someStatic;
+ $this->someStaticMethod->someStatic;
}
}
```
<br>
### LocallyCalledStaticMethodToNonStaticRector
Change static method and local-only calls to non-static

View File

@ -2,15 +2,11 @@
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\PSR4\Composer\PSR4NamespaceMatcher;
use Rector\PSR4\Contract\PSR4AutoloadNamespaceMatcherInterface;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_REMOVE_STATIC_FROM, []);
$services = $containerConfigurator->services();
$services->defaults()
@ -22,5 +18,11 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->alias(PSR4AutoloadNamespaceMatcherInterface::class, PSR4NamespaceMatcher::class);
$services->load('Rector\\', __DIR__ . '/../rules')
->exclude([__DIR__ . '/../rules/*/{ValueObject,Rector,Contract,Exception,Enum}']);
->exclude([
__DIR__ . '/../rules/*/ValueObject/*',
__DIR__ . '/../rules/*/Rector/*',
__DIR__ . '/../rules/*/Contract/*',
__DIR__ . '/../rules/*/Exception/*',
__DIR__ . '/../rules/*/Enum/*',
]);
};

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DesiredClassTypeToDynamicRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/some_config.php';
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Source\FirstStaticClass;
class AnotherClass
{
public function run()
{
FirstStaticClass::someStaticFunction();
}
}
?>
-----
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Source\FirstStaticClass;
class AnotherClass
{
public function __construct(private \Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Source\FirstStaticClass $firstStaticClass)
{
}
public function run()
{
FirstStaticClass::someStaticFunction();
}
}
?>

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Source;
final class FirstStaticClass
{
public static function someStaticFunction()
{
}
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector;
use Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\Source\FirstStaticClass;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_REMOVE_STATIC_FROM, [FirstStaticClass::class]);
$services = $containerConfigurator->services();
$services->set(DesiredClassTypeToDynamicRector::class);
};

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DesiredPropertyClassMethodTypeToDynamicRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/some_config.php';
}
}

View File

@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector\Fixture;
final class StaticProperty
{
public static $value;
}
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector\Fixture;
final class StaticProperty
{
public $value;
}
?>

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector;
use Rector\Tests\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector\Fixture\StaticProperty;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_REMOVE_STATIC_FROM, [StaticProperty::class]);
$services = $containerConfigurator->services();
$services->set(DesiredPropertyClassMethodTypeToDynamicRector::class);
};

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DesiredStaticCallTypeToDynamicRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/some_config.php';
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Source\SomeStaticMethod;
final class SomeStaticCall
{
public function run()
{
SomeStaticMethod::go();
}
}
?>
-----
<?php
namespace Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Source\SomeStaticMethod;
final class SomeStaticCall
{
public function run()
{
$this->someStaticMethod->go();
}
}
?>

View File

@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Source;
final class SomeStaticMethod
{
public static function go()
{
}
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector;
use Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\Source\SomeStaticMethod;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_REMOVE_STATIC_FROM, [SomeStaticMethod::class]);
$services = $containerConfigurator->services();
$services->set(DesiredStaticCallTypeToDynamicRector::class);
};

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DesiredStaticPropertyFetchTypeToDynamicRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/some_config.php';
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Source\SomeStaticType;
final class SomeStaticPropertyFetch
{
public function run()
{
return SomeStaticType::$someProperty;
}
}
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Source\SomeStaticType;
final class SomeStaticPropertyFetch
{
public function __construct(private \Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Source\SomeStaticType $someStaticType)
{
}
public function run()
{
return $this->someStaticType->someProperty;
}
}
?>

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Source;
final class SomeStaticType
{
public static $someProperty;
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector;
use Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\Source\SomeStaticType;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::TYPES_TO_REMOVE_STATIC_FROM, [SomeStaticType::class]);
$services = $containerConfigurator->services();
$services->set(DesiredStaticPropertyFetchTypeToDynamicRector::class);
};

View File

@ -1,53 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class StaticCallPresenceAnalyzer
{
public function __construct(
private readonly BetterNodeFinder $betterNodeFinder,
private readonly NodeTypeResolver $nodeTypeResolver
) {
}
public function hasMethodStaticCallOnType(ClassMethod $classMethod, ObjectType $objectType): bool
{
return (bool) $this->betterNodeFinder->findFirst(
(array) $classMethod->stmts,
function (Node $node) use ($objectType): bool {
if (! $node instanceof StaticCall) {
return false;
}
return $this->nodeTypeResolver->isObjectType($node->class, $objectType);
}
);
}
public function hasClassAnyMethodWithStaticCallOnType(Class_ $class, ObjectType $objectType): bool
{
foreach ($class->getMethods() as $classMethod) {
// handled else where
if ((string) $classMethod->name === MethodName::CONSTRUCT) {
continue;
}
if ($this->hasMethodStaticCallOnType($classMethod, $objectType)) {
return true;
}
}
return false;
}
}

View File

@ -1,190 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use Rector\Core\Configuration\Option;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Naming\Naming\PropertyNaming;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\RemovingStatic\NodeAnalyzer\StaticCallPresenceAnalyzer;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\RemovingStatic\Rector\Class_\DesiredClassTypeToDynamicRector\DesiredClassTypeToDynamicRectorTest
*/
final class DesiredClassTypeToDynamicRector extends AbstractRector
{
/**
* @var ObjectType[]
*/
private array $staticObjectTypes = [];
public function __construct(
private readonly PropertyNaming $propertyNaming,
private readonly StaticCallPresenceAnalyzer $staticCallPresenceAnalyzer,
private readonly PropertyToAddCollector $propertyToAddCollector,
ParameterProvider $parameterProvider
) {
$typesToRemoveStaticFrom = $parameterProvider->provideArrayParameter(Option::TYPES_TO_REMOVE_STATIC_FROM);
foreach ($typesToRemoveStaticFrom as $typeToRemoveStaticFrom) {
$this->staticObjectTypes[] = new ObjectType($typeToRemoveStaticFrom);
}
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change full static service, to dynamic one', [
new CodeSample(
<<<'CODE_SAMPLE'
class AnotherClass
{
public function run()
{
SomeClass::someStatic();
}
}
class SomeClass
{
public static function run()
{
self::someStatic();
}
private static function someStatic()
{
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class AnotherClass
{
/**
* @var SomeClass
*/
private $someClass;
public fuction __construct(SomeClass $someClass)
{
$this->someClass = $someClass;
}
public function run()
{
SomeClass::someStatic();
}
}
class SomeClass
{
public function run()
{
$this->someStatic();
}
private function someStatic()
{
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
foreach ($this->staticObjectTypes as $staticObjectType) {
// do not any dependencies to class itself
if ($this->isObjectType($node, $staticObjectType)) {
continue;
}
$this->completeDependencyToConstructorOnly($node, $staticObjectType);
if ($this->staticCallPresenceAnalyzer->hasClassAnyMethodWithStaticCallOnType($node, $staticObjectType)) {
$propertyExpectedName = $this->propertyNaming->fqnToVariableName($staticObjectType);
$propertyMetadata = new PropertyMetadata(
$propertyExpectedName,
$staticObjectType,
Class_::MODIFIER_PRIVATE
);
$this->propertyToAddCollector->addPropertyToClass($node, $propertyMetadata);
return $node;
}
}
return null;
}
private function completeDependencyToConstructorOnly(Class_ $class, ObjectType $objectType): void
{
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
if (! $constructClassMethod instanceof ClassMethod) {
return;
}
$hasStaticCall = $this->staticCallPresenceAnalyzer->hasMethodStaticCallOnType(
$constructClassMethod,
$objectType
);
if (! $hasStaticCall) {
return;
}
$propertyExpectedName = $this->propertyNaming->fqnToVariableName($objectType);
if ($this->isTypeAlreadyInParamMethod($constructClassMethod, $objectType)) {
return;
}
$constructClassMethod->params[] = $this->createParam($propertyExpectedName, $objectType);
}
private function isTypeAlreadyInParamMethod(ClassMethod $classMethod, ObjectType $objectType): bool
{
foreach ($classMethod->getParams() as $param) {
if ($param->type === null) {
continue;
}
if ($this->isName($param->type, $objectType->getClassName())) {
return true;
}
}
return false;
}
private function createParam(string $propertyName, ObjectType $objectType): Param
{
return new Param(new Variable($propertyName), null, new FullyQualified($objectType->getClassName()));
}
}

View File

@ -1,109 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\Rector\Property;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ObjectType;
use Rector\Core\Configuration\Option;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\RemovingStatic\Rector\Property\DesiredPropertyClassMethodTypeToDynamicRector\DesiredPropertyClassMethodTypeToDynamicRectorTest
*/
final class DesiredPropertyClassMethodTypeToDynamicRector extends AbstractRector
{
/**
* @var ObjectType[]
*/
private array $staticObjectTypes = [];
public function __construct(
ParameterProvider $parameterProvider,
private readonly VisibilityManipulator $visibilityManipulator,
) {
$typesToRemoveStaticFrom = $parameterProvider->provideArrayParameter(Option::TYPES_TO_REMOVE_STATIC_FROM);
foreach ($typesToRemoveStaticFrom as $typeToRemoveStaticFrom) {
$this->staticObjectTypes[] = new ObjectType($typeToRemoveStaticFrom);
}
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change defined static properties and methods to dynamic', [
new CodeSample(
<<<'CODE_SAMPLE'
final class SomeClass
{
public static $name;
public static function go()
{
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
final class SomeClass
{
public $name;
public function go()
{
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Property::class, ClassMethod::class];
}
/**
* @param Property|ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
/** @var Scope $scope */
$scope = $node->getAttribute(AttributeKey::SCOPE);
$classReflection = $scope->getClassReflection();
if (! $classReflection instanceof ClassReflection) {
return null;
}
$classObjectType = new ObjectType($classReflection->getName());
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $staticObjectType->isSuperTypeOf($classObjectType)->yes()) {
continue;
}
if (! $node->isStatic()) {
return null;
}
$this->visibilityManipulator->makeNonStatic($node);
return $node;
}
return null;
}
}

View File

@ -1,116 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\Rector\StaticCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;
use Rector\Core\Configuration\Option;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Naming\Naming\PropertyNaming;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\RemovingStatic\Rector\StaticCall\DesiredStaticCallTypeToDynamicRector\DesiredStaticCallTypeToDynamicRectorTest
*/
final class DesiredStaticCallTypeToDynamicRector extends AbstractRector
{
/**
* @var ObjectType[]
*/
private array $staticObjectTypes = [];
public function __construct(
private readonly PropertyNaming $propertyNaming,
ParameterProvider $parameterProvider
) {
$typesToRemoveStaticFrom = $parameterProvider->provideArrayParameter(Option::TYPES_TO_REMOVE_STATIC_FROM);
foreach ($typesToRemoveStaticFrom as $typeToRemoveStaticFrom) {
$this->staticObjectTypes[] = new ObjectType($typeToRemoveStaticFrom);
}
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change defined static service to dynamic one', [
new CodeSample(
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
SomeStaticMethod::someStatic();
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
$this->someStaticMethod->someStatic();
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [StaticCall::class];
}
/**
* @param StaticCall $node
*/
public function refactor(Node $node): ?Node
{
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $this->isObjectType($node->class, $staticObjectType)) {
continue;
}
// is the same class or external call?
$className = $this->getName($node->class);
if ($className === 'self') {
return $this->createFromSelf($node);
}
$propertyName = $this->propertyNaming->fqnToVariableName($staticObjectType);
$classMethod = $this->betterNodeFinder->findParentType($node, ClassMethod::class);
if (! $classMethod instanceof ClassMethod) {
return null;
}
if ($this->nodeNameResolver->isName($classMethod, MethodName::CONSTRUCT)) {
$propertyFetch = new Variable($propertyName);
} else {
$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
}
return new MethodCall($propertyFetch, $node->name, $node->args);
}
return null;
}
private function createFromSelf(StaticCall $staticCall): MethodCall
{
return new MethodCall(new Variable('this'), $staticCall->name, $staticCall->args);
}
}

View File

@ -1,125 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\Rector\StaticPropertyFetch;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ObjectType;
use Rector\Core\Configuration\Option;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\RemovingStatic\Rector\StaticPropertyFetch\DesiredStaticPropertyFetchTypeToDynamicRector\DesiredStaticPropertyFetchTypeToDynamicRectorTest
*/
final class DesiredStaticPropertyFetchTypeToDynamicRector extends AbstractRector
{
/**
* @var ObjectType[]
*/
private array $staticObjectTypes = [];
public function __construct(
private readonly PropertyNaming $propertyNaming,
private readonly PropertyToAddCollector $propertyToAddCollector,
ParameterProvider $parameterProvider
) {
$typesToRemoveStaticFrom = $parameterProvider->provideArrayParameter(Option::TYPES_TO_REMOVE_STATIC_FROM);
foreach ($typesToRemoveStaticFrom as $typeToRemoveStaticFrom) {
$this->staticObjectTypes[] = new ObjectType($typeToRemoveStaticFrom);
}
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change defined static service to dynamic one', [
new CodeSample(
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
SomeStaticMethod::$someStatic;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
final class SomeClass
{
public function run()
{
$this->someStaticMethod->someStatic;
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [StaticPropertyFetch::class];
}
/**
* @param StaticPropertyFetch $node
*/
public function refactor(Node $node): ?Node
{
/** @var Scope $scope */
$scope = $node->getAttribute(AttributeKey::SCOPE);
$classReflection = $scope->getClassReflection();
if (! $classReflection instanceof ClassReflection) {
return null;
}
$classObjectType = new ObjectType($classReflection->getName());
// A. remove local fetch
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $staticObjectType->isSuperTypeOf($classObjectType)->yes()) {
continue;
}
return new PropertyFetch(new Variable('this'), $node->name);
}
// B. external property fetch
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $this->isObjectType($node->class, $staticObjectType)) {
continue;
}
$propertyName = $this->propertyNaming->fqnToVariableName($staticObjectType);
/** @var Class_ $class */
$class = $this->betterNodeFinder->findParentType($node, Class_::class);
$propertyMetadata = new PropertyMetadata($propertyName, $staticObjectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
$objectPropertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
return new PropertyFetch($objectPropertyFetch, $node->name);
}
return null;
}
}

View File

@ -141,11 +141,6 @@ final class Option
*/
public const PHPSTAN_FOR_RECTOR_PATH = 'phpstan_for_rector_path';
/**
* @var string
*/
public const TYPES_TO_REMOVE_STATIC_FROM = 'types_to_remove_static_from';
/**
* @var string
*/