Skip to content

Commit 2f96832

Browse files
committed
[DowngradePhp83] Add DowngradeDynamicClassConstFetchRector
1 parent 2910a2a commit 2f96832

6 files changed

Lines changed: 166 additions & 0 deletions

File tree

config/set/downgrade-php83.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
use Rector\DowngradePhp83\Rector\Class_\DowngradeReadonlyAnonymousClassRector;
77
use Rector\ValueObject\PhpVersion;
88
use Rector\DowngradePhp83\Rector\ClassConst\DowngradeTypedClassConstRector;
9+
use Rector\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector;
910

1011
return static function (RectorConfig $rectorConfig): void {
1112
$rectorConfig->phpVersion(PhpVersion::PHP_82);
1213
$rectorConfig->rules([
1314
DowngradeTypedClassConstRector::class,
1415
DowngradeReadonlyAnonymousClassRector::class,
16+
DowngradeDynamicClassConstFetchRector::class,
1517
]);
1618
};
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\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class DowngradeDynamicClassConstFetchRectorTest 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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector\Fixture;
6+
7+
class Fixture
8+
{
9+
public const string FOO = 'foo';
10+
11+
public function run()
12+
{
13+
$someValue = 'foo';
14+
Fixture::{$someValue};
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
declare(strict_types=1);
23+
24+
namespace Rector\Tests\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector\Fixture;
25+
26+
class Fixture
27+
{
28+
public const string FOO = 'foo';
29+
30+
public function run()
31+
{
32+
$someValue = 'foo';
33+
constant(Fixture::class . '::' . $someValue);
34+
}
35+
}
36+
37+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector\Fixture;
6+
7+
class SkipNamedClassConstFetch
8+
{
9+
public const FOO = 'foo';
10+
11+
public function run()
12+
{
13+
return self::FOO;
14+
}
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(DowngradeDynamicClassConstFetchRector::class);
10+
};
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\DowngradePhp83\Rector\ClassConstFetch;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\BinaryOp\Concat;
9+
use PhpParser\Node\Expr\ClassConstFetch;
10+
use PhpParser\Node\Identifier;
11+
use PhpParser\Node\Scalar\String_;
12+
use Rector\NodeManipulator\PropertyDecorator;
13+
use Rector\Rector\AbstractRector;
14+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
15+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
16+
17+
/**
18+
* @changelog https://wiki.php.net/rfc/dynamic_class_constant_fetch
19+
*
20+
* @see \Rector\Tests\DowngradePhp83\Rector\ClassConstFetch\DowngradeDynamicClassConstFetchRector\DowngradeDynamicClassConstFetchRectorTest
21+
*/
22+
final class DowngradeDynamicClassConstFetchRector extends AbstractRector
23+
{
24+
public function __construct(
25+
private readonly PropertyDecorator $propertyDecorator
26+
) {
27+
}
28+
29+
/**
30+
* @return array<class-string<Node>>
31+
*/
32+
public function getNodeTypes(): array
33+
{
34+
return [ClassConstFetch::class];
35+
}
36+
37+
public function getRuleDefinition(): RuleDefinition
38+
{
39+
return new RuleDefinition(
40+
'Change dynamic class const fetch Example::{$constName} to constant(Example::class . \'::\' . $constName)',
41+
[
42+
new CodeSample(
43+
<<<'CODE_SAMPLE'
44+
$value = Example::{$constName};
45+
CODE_SAMPLE
46+
,
47+
<<<'CODE_SAMPLE'
48+
$value = constant(Example::class . '::' . $constName);
49+
CODE_SAMPLE
50+
),
51+
]
52+
);
53+
}
54+
55+
/**
56+
* @param ClassConstFetch $node
57+
*/
58+
public function refactor(Node $node): ?Node
59+
{
60+
if ($node->name instanceof Identifier) {
61+
return null;
62+
}
63+
64+
return $this->nodeFactory->createFuncCall('constant', [
65+
new Concat(
66+
new Concat(
67+
new ClassConstFetch($node->class, new Identifier('class')),
68+
new String_('::')
69+
),
70+
$node->name
71+
),
72+
]);
73+
}
74+
}

0 commit comments

Comments
 (0)