10000 [Php83] Add DynamicClassConstFetchRector (#6922) · rectorphp/rector-src@9f3665a · GitHub
[go: up one dir, main page]

Skip to content

Commit 9f3665a

Browse files
authored
[Php83] Add DynamicClassConstFetchRector (#6922)
* [Php83] Add DynamicClassConstFetchRector * [Php83] Add DynamicClassConstFetchRector * [Php83] Add DynamicClassConstFetchRector
1 parent f1dfb89 commit 9f3665a

File tree

8 files changed

+196
-2
lines changed

8 files changed

+196
-2
lines changed

config/set/php83.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Rector\Php83\Rector\ClassConst\AddTypeToConstRector;
88
use Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector;
99
use Rector\Php83\Rector\FuncCall\CombineHostPortLdapUriRector;
10+
use Rector\Php83\Rector\FuncCall\DynamicClassConstFetchRector;
1011
use Rector\Php83\Rector\FuncCall\RemoveGetClassGetParentClassNoArgsRector;
1112

1213
return static function (RectorConfig $rectorConfig): void {
@@ -16,5 +17,6 @@
1617
CombineHostPortLdapUriRector::class,
1718
RemoveGetClassGetParentClassNoArgsRector::class,
1819
ReadOnlyAnonymousClassRector::class,
20+
DynamicClassConstFetchRector::class,
1921
]);
2022
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\Php83\Rector\FuncCall\DynamicClassConstFetchRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class DynamicClassConstFetchRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php83\Rector\FuncCall\DynamicClassConstFetchRector\Fixture;
4+
5+
class Fixture
6+
{
7+
public const SOME_CONST = 'some_value';
8+
9+
public function test()
10+
{
11+
$constName = 'SOME_CONST';
12+
constant(Fixture::class . '::' . $constName);
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\Php83\Rector\FuncCall\DynamicClassConstFetchRector\Fixture;
21+
22+
class Fixture
23+
{
24+
public const SOME_CONST = 'some_value';
25+
26+
public function test()
27+
{
28+
$constName = 'SOME_CONST';
29+
Fixture::{$constName};
30+
}
31+
}
32+
33+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\Tests\Php83\Rector\FuncCall\DynamicClassConstFetchRector\Fixture;
4+
5+
class SkipDynamicClassConstFetch
6 9E88 +
{
7+
public const SOME_CONST = 'some_value';
8+
9+
public function test()
10+
{
11+
$constName = 'SOME_CONST';
12+
SkipDynamicClassConstFetch::{$constName};
13+
}
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Php83\Rector\FuncCall\DynamicClassConstFetchRector;
7+
use Rector\ValueObject\PhpVersion;
8+
9+
return static function (RectorConfig $rectorConfig): void {
10+
$rectorConfig->rule(DynamicClassConstFetchRector::class);
11+
12+
$rectorConfig->phpVersion(PhpVersion::PHP_83);
13+
};
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Php83\Rector\FuncCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\BinaryOp\Concat;
9+
use PhpParser\Node\Expr\ClassConstFetch;
10+
use PhpParser\Node\Expr\FuncCall;
11+
use PhpParser\Node\Identifier;
12+
use PhpParser\Node\Scalar\String_;
13+
use Rector\Rector\AbstractRector;
14+
use Rector\ValueObject\PhpVersionFeature;
15+
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
16+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
17+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
18+
19+
/**
20+
* @see \Rector\Tests\Php83\Rector\FuncCall\DynamicClassConstFetchRector\DynamicClassConstFetchRectorTest
21+
*/
22+
final class DynamicClassConstFetchRector extends AbstractRector implements MinPhpVersionInterface
23+
{
24+
public function getRuleDefinition(): RuleDefinition
25+
{
26+
return new RuleDefinition(
27+
'constant(Example::class . \'::\' . $constName) to dynamic class const fetch Example::{$constName}',
28+
[
29+
new CodeSample(
30+
<<<'CODE_SAMPLE'
31+
constant(Example::class . '::' . $constName);
32+
CODE_SAMPLE
33+
,
34+
<<<'CODE_SAMPLE'
35+
Example::{$constName};
36+
CODE_SAMPLE
37+
,
38+
),
39+
40+
]);
41+
}
42+
43+
public function getNodeTypes(): array
44+
{
45+
return [FuncCall::class];
46+
}
47+
48+
/**
49+
* @param FuncCall $node
50+
*/
51+
public function refactor(Node $node): ?ClassConstFetch
52+
{
53+
if (! $this->isName($node, 'constant')) {
54+
return null;
55+
}
56+
57+
if ($node->isFirstClassCallable()) {
58+
return null;
59+
}
60+
61+
$args = $node->getArgs();
62+
if (count($args) !== 1) {
63+
return null;
64+
}
65+
66+
$value = $args[0]->value;
67+
if (! $value instanceof Concat) {
68+
return null;
69+
}
70+
71+
if (! $value->left instanceof Concat) {
72+
return null;
73+
}
74+
75+
if (! $value->left->left instanceof ClassConstFetch) {
76+
return null;
77+
}
78+
79+
if (! $value->left->left->name instanceof Identifier || $value->left->left->name->toString() !== 'class') {
80+
return null;
81+
}
82+
83+
if (! $value->left->right instanceof String_ || $value->left->right->value !== '::') {
84+
return null;
85+
}
86+
87+
return new ClassConstFetch($value->left->left->class, $value->right);
88+
}
89+
90+
public function provideMinPhpVersion(): int
91+
{
92+
return PhpVersionFeature::DYNAMIC_CLASS_CONST_FETCH;
93+
}
94+
}

src/NodeManipulator/ClassConstManipulator.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ public function hasClassConstFetch(ClassConst $classConst, ClassReflection $clas
6363
return false;
6464
}
6565

66-
private function isNameMatch(ClassConstFetch $classConstFetch, ClassConst $classConst, string $className, ObjectType $objectType): bool
67-
{
66+
private function isNameMatch(
67+
ClassConstFetch $classConstFetch,
68+
ClassConst $classConst,
69+
string $className,
70+
ObjectType $objectType
71+
): bool {
6872
$classConstName = (string) $this->nodeNameResolver->getName($classConst);
6973
$selfConstantName = 'self::' . $classConstName;
7074
$staticConstantName = 'static::' . $classConstName;

src/ValueObject/PhpVersionFeature.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,12 @@ final class PhpVersionFeature
690690
*/
691691
public const TYPED_CLASS_CONSTANTS = PhpVersion::PHP_83;
692692

693+
/**
694+
* @see https://wiki.php.net/rfc/dynamic_class_constant_fetch
695+
* @var int
696+
*/
697+
public const DYNAMIC_CLASS_CONST_FETCH = PhpVersion::PHP_83;
698+
693699
/**
694700
* @see https://wiki.php.net/rfc/deprecate-implicitly-nullable-types
695701
* @var int

0 commit comments

Comments
 (0)
0