17
17
use Go \ParserReflection \Traits \ReflectionClassLikeTrait ;
18
18
use PhpParser \Node \Name \FullyQualified ;
19
19
use PhpParser \Node \Stmt \ClassLike ;
20
+ use PhpParser \Node \Stmt \Enum_ ;
20
21
use PhpParser \Node \Stmt \Interface_ ;
21
22
use PhpParser \Node \Stmt \TraitUse ;
22
23
use ReflectionClass as InternalReflectionClass ;
23
24
24
25
/**
25
26
* AST-based reflection class
27
+ * @see \Go\ParserReflection\ReflectionClassTest
26
28
*/
27
29
class ReflectionClass extends InternalReflectionClass
28
30
{
@@ -33,10 +35,10 @@ class ReflectionClass extends InternalReflectionClass
33
35
/**
34
36
* Initializes reflection instance
35
37
*
36
- * @param string| object $argument Class name or instance of object
38
+ * @param object|string $argument Class name or instance of object
37
39
* @param ?ClassLike $classLikeNode AST node for class
38
40
*/
39
- public function __construct ($ argument , ClassLike $ classLikeNode = null )
41
+ public function __construct (object | string $ argument , ? ClassLike $ classLikeNode = null )
40
42
{
41
43
$ fullClassName = is_object ($ argument ) ? get_class ($ argument ) : ltrim ($ argument , '\\' );
42
44
$ namespaceParts = explode ('\\' , $ fullClassName );
@@ -60,9 +62,11 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):
60
62
61
63
$ isInterface = $ classLikeNode instanceof Interface_;
62
64
$ interfaceField = $ isInterface ? 'extends ' : 'implements ' ;
63
- $ hasInterfaces = in_array ($ interfaceField , $ classLikeNode ->getSubNodeNames (), true );
64
- $ implementsList = $ hasInterfaces ? $ classLikeNode ->$ interfaceField : [];
65
- if ($ implementsList ) {
65
+
66
+ $ hasExplicitInterfaces = in_array ($ interfaceField , $ classLikeNode ->getSubNodeNames (), true );
67
+ $ implementsList = $ hasExplicitInterfaces ? $ classLikeNode ->$ interfaceField : [];
68
+
69
+ if (count ($ implementsList ) > 0 ) {
66
70
foreach ($ implementsList as $ implementNode ) {
67
71
if ($ implementNode instanceof FullyQualified) {
68
72
$ implementName = $ implementNode ->toString ();
@@ -75,6 +79,17 @@ public static function collectInterfacesFromClassNode(ClassLike $classLikeNode):
75
79
}
76
80
}
77
81
82
+ // All Enum classes has implicit interface(s) added by PHP
83
+ if ($ classLikeNode instanceof Enum_) {
84
+ // @see https://php.watch/versions/8.1/enums#enum-BackedEnum
85
+ $ interfacesToAdd = isset ($ classLikeNode ->scalarType )
86
+ ? [\UnitEnum::class, \BackedEnum::class] // PHP Uses exactly this order, not reversed by parent!
87
+ : [\UnitEnum::class];
88
+ foreach ($ interfacesToAdd as $ interfaceToAdd ) {
89
+ $ interfaces [$ interfaceToAdd ] = new parent ($ interfaceToAdd );
90
+ }
91
+ }
92
+
78
93
return $ interfaces ;
79
94
}
80
95
@@ -129,8 +144,6 @@ public function getNode(): ?ClassLike
129
144
130
145
/**
131
146
* Implementation of internal reflection initialization
132
- *
133
- * @return void
134
147
*/
135
148
protected function __initialize (): void
136
149
{
@@ -140,12 +153,11 @@ protected function __initialize(): void
140
153
/**
141
154
* Create a ReflectionClass for a given class name.
142
155
*
143
- * @param string $className
144
- * The name of the class to create a reflection for.
156
+ * @param string $className The name of the class to create a reflection for.
145
157
*
146
158
* @return InternalReflectionClass The appropriate reflection object.
147
159
*/
148
- protected function createReflectionForClass (string $ className )
160
+ protected function createReflectionForClass (string $ className ): InternalReflectionClass
149
161
{
150
162
return class_exists ($ className , false ) ? new parent ($ className ) : new static ($ className );
151
163
}
0 commit comments