Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8c22f24

Browse files
Bleeding edge - BetterReflectionProvider
Use PHPStan's static reflection instead of runtime reflection.
1 parent 3dbb999 commit 8c22f24

17 files changed

+145
-13
lines changed

‎extension.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ services:
9696
class: PHPStan\Type\Doctrine\ObjectMetadataResolver
9797
arguments:
9898
objectManagerLoader: %doctrine.objectManagerLoader%
99+
bleedingEdge: %featureToggles.bleedingEdge%
99100
-
100101
class: PHPStan\Type\Doctrine\QueryBuilder\QueryBuilderGetDqlDynamicReturnTypeExtension
101102
arguments:

‎phpcs.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
</rule>
3434
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint">
3535
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingTraversableTypeHintSpecification"/>
36+
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint"/>
3637
<exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint"/>
3738
</rule>
3839
<rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint.UselessAnnotation">

‎phpstan-baseline.neon

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
parameters:
22
ignoreErrors:
3+
-
4+
message: "#^Method PHPStan\\\\Doctrine\\\\Mapping\\\\BetterReflectionService\\:\\:getParentClasses\\(\\) should return array\\<class\\-string\\> but returns array\\<string\\>\\.$#"
5+
count: 1
6+
path: src/Doctrine/Mapping/BetterReflectionService.php
7+
8+
-
9+
message: "#^PHPDoc tag @var with type ReflectionClass\\<T of object\\> is not subtype of type PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionClass\\|PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#"
10+
count: 1
11+
path: src/Doctrine/Mapping/BetterReflectionService.php
12+
313
-
414
message: "#^Calling PHPStan\\\\Type\\\\ParserNodeTypeToPHPStanType\\:\\:resolve\\(\\) is not covered by backward compatibility promise\\. The method might change in a minor PHPStan version\\.$#"
515
count: 1
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Doctrine\Mapping;
4+
5+
use Doctrine\Persistence\Mapping\MappingException;
6+
use Doctrine\Persistence\Mapping\ReflectionService;
7+
use PHPStan\Reflection\ReflectionProvider;
8+
use ReflectionClass;
9+
10+
class BetterReflectionService implements ReflectionService
11+
{
12+
13+
/** @var ReflectionProvider */
14+
private $reflectionProvider;
15+
16+
public function __construct(ReflectionProvider $reflectionProvider)
17+
{
18+
$this->reflectionProvider = $reflectionProvider;
19+
}
20+
21+
public function getParentClasses($class)
22+
{
23+
if (!$this->reflectionProvider->hasClass($class)) {
24+
throw MappingException::nonExistingClass($class);
25+
}
26+
27+
$classReflection = $this->reflectionProvider->getClass($class);
28+
29+
return $classReflection->getParentClassesNames();
30+
}
31+
32+
public function getClassShortName($class)
33+
{
34+
return $this->getClass($class)->getShortName();
35+
}
36+
37+
public function getClassNamespace($class)
38+
{
39+
return $this->getClass($class)->getNamespaceName();
40+
}
41+
42+
/**
43+
* @param class-string<T> $class
44+
* @return ReflectionClass<T>
45+
*
46+
* @template T of object
47+
*/
48+
public function getClass($class)
49+
{
50+
if (!$this->reflectionProvider->hasClass($class)) {
51+
throw MappingException::nonExistingClass($class);
52+
}
53+
54+
$classReflection = $this->reflectionProvider->getClass($class);
55+
56+
/** @var ReflectionClass<T> */
57+
return $classReflection->getNativeReflection();
58+
}
59+
60+
public function getAccessibleProperty($class, $property)
61+
{
62+
$classReflection = $this->getClass($class);
63+
$property = $classReflection->getProperty($property);
64+
$property->setAccessible(true);
65+
66+
return $property;
67+
}
68+
69+
public function hasPublicMethod($class, $method)
70+
{
71+
$classReflection = $this->getClass($class);
72+
if (!$classReflection->hasMethod($method)) {
73+
return false;
74+
}
75+
76+
return $classReflection->getMethod($method)->isPublic();
77+
}
78+
79+
}

‎src/Doctrine/Mapping/ClassMetadataFactory.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use Doctrine\ORM\Mapping\ClassMetadata;
1010
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
1111
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
12+
use Doctrine\Persistence\Mapping\ReflectionService;
13+
use PHPStan\Reflection\ReflectionProvider;
1214
use ReflectionClass;
1315
use function class_exists;
1416
use function count;
@@ -17,6 +19,21 @@
1719
class ClassMetadataFactory extends \Doctrine\ORM\Mapping\ClassMetadataFactory
1820
{
1921

22+
/** @var ReflectionProvider */
23+
private $reflectionProvider;
24+
25+
/** @var bool */
26+
private $bleedingEdge;
27+
28+
/** @var BetterReflectionService|null */
29+
private $reflectionService = null;
30+
31+
public function __construct(ReflectionProvider $reflectionProvider, bool $bleedingEdge)
32+
{
33+
$this->reflectionProvider = $reflectionProvider;
34+
$this->bleedingEdge = $bleedingEdge;
35+
}
36+
2037
protected function initialize(): void
2138
{
2239
$parentReflection = new ReflectionClass(parent::class);
@@ -52,6 +69,19 @@ protected function initialize(): void
5269
$targetPlatformProperty->setValue($this, $platform);
5370
}
5471

72+
public function getReflectionService(): ReflectionService
73+
{
74+
if (!$this->bleedingEdge) {
75+
return parent::getReflectionService();
76+
}
77+
78+
if ($this->reflectionService === null) {
79+
$this->reflectionService = new BetterReflectionService($this->reflectionProvider);
80+
}
81+
82+
return $this->reflectionService;
83+
}
84+
5585
/**
5686
* @template T of object
5787
* @param class-string<T> $className

‎src/Type/Doctrine/ObjectMetadataResolver.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Doctrine\ORM\Mapping\MappingException;
88
use Doctrine\Persistence\ObjectManager;
99
use PHPStan\Doctrine\Mapping\ClassMetadataFactory;
10+
use PHPStan\Reflection\ReflectionProvider;
1011
use PHPStan\ShouldNotHappenException;
1112
use ReflectionException;
1213
use function class_exists;
@@ -17,20 +18,30 @@
1718
final class ObjectMetadataResolver
1819
{
1920

21+
/** @var ReflectionProvider */
22+
private $reflectionProvider;
23+
2024
/** @var string|null */
2125
private $objectManagerLoader;
2226

27+
/** @var bool */
28+
private $bleedingEdge;
29+
2330
/** @var ObjectManager|false|null */
2431
private $objectManager;
2532

2633
/** @var ClassMetadataFactory|null */
2734
private $metadataFactory;
2835

2936
public function __construct(
30-
?string $objectManagerLoader
37+
ReflectionProvider $reflectionProvider,
38+
?string $objectManagerLoader,
39+
bool $bleedingEdge
3140
)
3241
{
42+
$this->reflectionProvider = $reflectionProvider;
3343
$this->objectManagerLoader = $objectManagerLoader;
44+
$this->bleedingEdge = $bleedingEdge;
3445
}
3546

3647
public function hasObjectManagerLoader(): bool
@@ -97,7 +108,7 @@ private function getMetadataFactory(): ?ClassMetadataFactory
97108
return null;
98109
}
99110

100-
return $this->metadataFactory = new ClassMetadataFactory();
111+
return $this->metadataFactory = new ClassMetadataFactory($this->reflectionProvider, $this->bleedingEdge);
101112
}
102113

103114
/**

‎tests/Rules/Doctrine/ORM/DqlRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class DqlRuleTest extends RuleTestCase
1414

1515
protected function getRule(): Rule
1616
{
17-
return new DqlRule(new ObjectMetadataResolver(__DIR__ . '/entity-manager.php'));
17+
return new DqlRule(new ObjectMetadataResolver($this->createReflectionProvider(), __DIR__ . '/entity-manager.php', true));
1818
}
1919

2020
public function testRule(): void

‎tests/Rules/Doctrine/ORM/EntityColumnRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected function getRule(): Rule
5656
}
5757

5858
return new EntityColumnRule(
59-
new ObjectMetadataResolver($this->objectManagerLoader),
59+
new ObjectMetadataResolver($this->createReflectionProvider(), $this->objectManagerLoader, true),
6060
new DescriptorRegistry([
6161
new ArrayType(),
6262
new BigIntType(),

‎tests/Rules/Doctrine/ORM/EntityMappingExceptionRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class EntityMappingExceptionRuleTest extends RuleTestCase
1616
protected function getRule(): Rule
1717
{
1818
return new EntityMappingExceptionRule(
19-
new ObjectMetadataResolver(__DIR__ . '/entity-manager.php')
19+
new ObjectMetadataResolver($this->createReflectionProvider(), __DIR__ . '/entity-manager.php', true)
2020
);
2121
}
2222

‎tests/Rules/Doctrine/ORM/EntityNotFinalRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class EntityNotFinalRuleTest extends RuleTestCase
1919
protected function getRule(): Rule
2020
{
2121
return new EntityNotFinalRule(
22-
new ObjectMetadataResolver($this->objectManagerLoader)
22+
new ObjectMetadataResolver($this->createReflectionProvider(), $this->objectManagerLoader, true)
2323
);
2424
}
2525

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /