Skip to content

Commit 1beef93

Browse files
authored
Handle getProperties()/getMethods() loop in DowngradeSetAccessibleReflectionPropertyRector (#396)
1 parent 70b30bb commit 1beef93

5 files changed

Lines changed: 192 additions & 0 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
4+
5+
class OnGetMethods
6+
{
7+
public function run($object)
8+
{
9+
$reflectionClass = new \ReflectionClass($object);
10+
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
11+
$reflectionMethod->invoke($object);
12+
}
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
21+
22+
class OnGetMethods
23+
{
24+
public function run($object)
25+
{
26+
$reflectionClass = new \ReflectionClass($object);
27+
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
28+
if (PHP_VERSION_ID < 80100) {
29+
$reflectionMethod->setAccessible(true);
30+
}
31+
$reflectionMethod->invoke($object);
32+
}
33+
}
34+
}
35+
36+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
4+
5+
class OnGetProperties
6+
{
7+
public function run($object)
8+
{
9+
$reflectionObject = new \ReflectionObject($object);
10+
foreach ($reflectionObject->getProperties() as $reflectionProperty) {
11+
echo $reflectionProperty->getValue($object);
12+
}
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
21+
22+
class OnGetProperties
23+
{
24+
public function run($object)
25+
{
26+
$reflectionObject = new \ReflectionObject($object);
27+
foreach ($reflectionObject->getProperties() as $reflectionProperty) {
28+
if (PHP_VERSION_ID < 80100) {
29+
$reflectionProperty->setAccessible(true);
30+
}
31+
echo $reflectionProperty->getValue($object);
32+
}
33+
}
34+
}
35+
36+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
4+
5+
class SkipAlreadyAccessibleInForeach
6+
{
7+
public function run($object)
8+
{
9+
$reflectionObject = new \ReflectionObject($object);
10+
foreach ($reflectionObject->getProperties() as $reflectionProperty) {
11+
if (PHP_VERSION_ID < 80100) {
12+
$reflectionProperty->setAccessible(true);
13+
}
14+
echo $reflectionProperty->getValue($object);
15+
}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp81\Rector\StmtsAwareInterface\DowngradeSetAccessibleReflectionPropertyRector\Fixture;
4+
5+
class SomeCollection
6+
{
7+
public function getProperties(): array
8+
{
9+
return [];
10+
}
11+
}
12+
13+
class SkipNonReflectionGetProperties
14+
{
15+
public function run()
16+
{
17+
$collection = new SomeCollection();
18+
foreach ($collection->getProperties() as $property) {
19+
echo $property;
20+
}
21+
}
22+
}

‎rules/DowngradePhp81/Rector/StmtsAwareInterface/DowngradeSetAccessibleReflectionPropertyRector.php‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
use PhpParser\Node\Scalar\Int_;
1717
use PhpParser\Node\Stmt;
1818
use PhpParser\Node\Stmt\Expression;
19+
use PhpParser\Node\Stmt\Foreach_;
1920
use PhpParser\Node\Stmt\If_;
2021
use PhpParser\Node\Stmt\Return_;
22+
use PHPStan\Type\ObjectType;
2123
use Rector\Naming\Naming\VariableNaming;
2224
use Rector\PhpParser\Enum\NodeGroup;
2325
use Rector\PHPStan\ScopeFetcher;
@@ -69,6 +71,38 @@ public function run($object)
6971
return $reflectionProperty->getValue($object);
7072
}
7173
}
74+
CODE_SAMPLE
75+
),
76+
77+
new CodeSample(
78+
<<<'CODE_SAMPLE'
79+
class SomeClass
80+
{
81+
public function run($object)
82+
{
83+
$reflectionObject = new ReflectionObject($object);
84+
foreach ($reflectionObject->getProperties() as $reflectionProperty) {
85+
echo $reflectionProperty->getValue($object);
86+
}
87+
}
88+
}
89+
CODE_SAMPLE
90+
91+
,
92+
<<<'CODE_SAMPLE'
93+
class SomeClass
94+
{
95+
public function run($object)
96+
{
97+
$reflectionObject = new ReflectionObject($object);
98+
foreach ($reflectionObject->getProperties() as $reflectionProperty) {
99+
if (PHP_VERSION_ID < 80100) {
100+
$reflectionProperty->setAccessible(true);
101+
}
102+
echo $reflectionProperty->getValue($object);
103+
}
104+
}
105+
}
72106
CODE_SAMPLE
73107
),
74108

@@ -96,6 +130,14 @@ public function refactor(Node $node): ?Node
96130
$hasChanged = false;
97131

98132
foreach ($node->stmts as $key => $stmt) {
133+
if ($stmt instanceof Foreach_) {
134+
if ($this->refactorForeach($stmt)) {
135+
$hasChanged = true;
136+
}
137+
138+
continue;
139+
}
140+
99141
if (! $stmt instanceof Expression && ! $stmt instanceof Return_) {
100142
continue;
101143
}
@@ -158,6 +200,45 @@ public function refactor(Node $node): ?Node
158200
return null;
159201
}
160202

203+
private function refactorForeach(Foreach_ $foreach): bool
204+
{
205+
if (! $foreach->valueVar instanceof Variable) {
206+
return false;
207+
}
208+
209+
if (! $this->isReflectionMembersCall($foreach->expr)) {
210+
return false;
211+
}
212+
213+
$firstStmt = $foreach->stmts[0] ?? null;
214+
if ($this->isSetAccessibleMethodCall($firstStmt) || $this->isSetAccessibleIfMethodCall($firstStmt)) {
215+
return false;
216+
}
217+
218+
array_unshift($foreach->stmts, $this->createSetAccessibleExpression($foreach->valueVar));
219+
220+
return true;
221+
}
222+
223+
private function isReflectionMembersCall(Expr $expr): bool
224+
{
225+
if (! $expr instanceof MethodCall) {
226+
return false;
227+
}
228+
229+
if (! $this->isNames($expr->name, ['getProperties', 'getMethods'])) {
230+
return false;
231+
}
232+
233+
$callerType = $this->nodeTypeResolver->getType($expr->var);
234+
if (! $callerType instanceof ObjectType) {
235+
return false;
236+
}
237+
238+
return $callerType->isInstanceOf('ReflectionClass')
239+
->yes();
240+
}
241+
161242
private function createSetAccessibleExpression(Expr $expr): If_
162243
{
163244
$args = [$this->nodeFactory->createArg($this->nodeFactory->createTrue())];

0 commit comments

Comments
 (0)