mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-14 12:29:43 +01:00
[PHP] Add StaticCallOnNonStaticToInstanceCallRector
This commit is contained in:
parent
d6a696196b
commit
dd5956bd9d
@ -18,3 +18,4 @@ services:
|
||||
Rector\Php\Rector\Switch_\ReduceMultipleDefaultSwitchRector: ~
|
||||
Rector\Php\Rector\Ternary\TernaryToSpaceshipRector: ~
|
||||
Rector\Php\Rector\If_\IfToSpaceshipRector: ~
|
||||
Rector\Php\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector: ~
|
||||
|
@ -52,4 +52,14 @@ final class FunctionLikeNodeCollector
|
||||
{
|
||||
return $this->methodsByType[$className][$methodName] ?? null;
|
||||
}
|
||||
|
||||
public function isStaticMethod(string $methodName, string $className): bool
|
||||
{
|
||||
$methodNode = $this->findMethod($methodName, $className);
|
||||
if ($methodNode === null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $methodNode->isStatic();
|
||||
}
|
||||
}
|
||||
|
@ -25,47 +25,27 @@ use Rector\RectorDefinition\RectorDefinition;
|
||||
final class IfToSpaceshipRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @var int|null
|
||||
=======
|
||||
* @var int
|
||||
>>>>>>> [PHP 7.3] Add IfToSpaceshipRector
|
||||
*/
|
||||
private $onEqual;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @var int|null
|
||||
=======
|
||||
* @var int
|
||||
>>>>>>> [PHP 7.3] Add IfToSpaceshipRector
|
||||
*/
|
||||
private $onSmaller;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @var int|null
|
||||
=======
|
||||
* @var int
|
||||
>>>>>>> [PHP 7.3] Add IfToSpaceshipRector
|
||||
*/
|
||||
private $onGreater;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @var Expr|null
|
||||
=======
|
||||
* @var Expr
|
||||
>>>>>>> [PHP 7.3] Add IfToSpaceshipRector
|
||||
*/
|
||||
private $firstValue;
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* @var Expr|null
|
||||
=======
|
||||
* @var Expr
|
||||
>>>>>>> [PHP 7.3] Add IfToSpaceshipRector
|
||||
*/
|
||||
private $secondValue;
|
||||
|
||||
|
@ -0,0 +1,115 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Rector\StaticCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use Rector\NodeTypeResolver\Application\FunctionLikeNodeCollector;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @see https://thephp.cc/news/2017/07/dont-call-instance-methods-statically
|
||||
* @see https://3v4l.org/tQ32f
|
||||
* @see https://stackoverflow.com/a/19694064/1348344
|
||||
*/
|
||||
final class StaticCallOnNonStaticToInstanceCallRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var FunctionLikeNodeCollector
|
||||
*/
|
||||
private $functionLikeNodeCollector;
|
||||
|
||||
public function __construct(FunctionLikeNodeCollector $functionLikeNodeCollector)
|
||||
{
|
||||
$this->functionLikeNodeCollector = $functionLikeNodeCollector;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Changes static call to instance call, where not useful', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class Something
|
||||
{
|
||||
public function doWork()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Another
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
return Something::doWork();
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class Something
|
||||
{
|
||||
public function doWork()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Another
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
return (new Something)->doWork();
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [StaticCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$isStaticMethod = $this->functionLikeNodeCollector->isStaticMethod($this->getName($node), $this->getName($node->class));
|
||||
if ($isStaticMethod) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->hasClassConstructorWithRequiredParameters($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$newNode = new New_($node->class);
|
||||
|
||||
return new MethodCall($newNode, $node->name);
|
||||
}
|
||||
|
||||
private function hasClassConstructorWithRequiredParameters(StaticCall $staticCallNode): bool
|
||||
{
|
||||
$className = $this->getName($staticCallNode->class);
|
||||
|
||||
$reflectionClass = new ReflectionClass($className);
|
||||
$classConstructorReflection = $reflectionClass->getConstructor();
|
||||
|
||||
if ($classConstructorReflection === null) {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// required parameters in constructor, nothing we can do
|
||||
return (bool) $classConstructorReflection->getNumberOfRequiredParameters();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php\Tests\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector\Fixture;
|
||||
|
||||
class Something
|
||||
{
|
||||
public function doWork()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Another
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
return Something::doWork();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php\Tests\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector\Fixture;
|
||||
|
||||
class Something
|
||||
{
|
||||
public function doWork()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Another
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
return (new Something())->doWork();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php\Tests\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector\Fixture;
|
||||
|
||||
class WithConstructor
|
||||
{
|
||||
public function __construct($required, $value = [])
|
||||
{
|
||||
}
|
||||
|
||||
public function doWork()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
class TryWithContructor
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
return WithConstructor::doWork();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php\Tests\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector;
|
||||
|
||||
use Rector\Php\Rector\StaticCall\StaticCallOnNonStaticToInstanceCallRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class StaticCallOnNonStaticToInstanceCallRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$this->doTestFiles([
|
||||
__DIR__ . '/Fixture/fixture.php.inc',
|
||||
__DIR__ . '/Fixture/with_constructor.php.inc',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return StaticCallOnNonStaticToInstanceCallRector::class;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user