@@ -37,43 +37,65 @@ public function fromClassReflection(
3737 throw new Nette \NotSupportedException ('The $withBodies parameter cannot be used for anonymous or internal classes or interfaces. ' );
3838 }
3939
40- $ enumIface = null ;
41- if ($ from ->isEnum ()) {
42- $ class = new EnumType ($ from ->getShortName (), new PhpNamespace ($ from ->getNamespaceName ()));
40+ $ class = $ this ->createClassObject ($ from );
41+ $ this ->setupInheritance ($ class , $ from );
42+ $ this ->populateMembers ($ class , $ from , $ withBodies );
43+ return $ class ;
44+ }
45+
46+
47+ /** @param \ReflectionClass<object> $from */
48+ private function createClassObject (\ReflectionClass &$ from ): ClassLike
49+ {
50+ if ($ from ->isAnonymous ()) {
51+ return new ClassType ;
52+ } elseif ($ from ->isEnum ()) {
4353 $ from = new \ReflectionEnum ($ from ->getName ());
44- $ enumIface = $ from ->isBacked () ? \BackedEnum::class : \UnitEnum::class;
45- } elseif ($ from ->isAnonymous ()) {
46- $ class = new ClassType ;
54+ $ class = new EnumType ($ from ->getName ());
4755 } elseif ($ from ->isInterface ()) {
48- $ class = new InterfaceType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName () ));
56+ $ class = new InterfaceType ($ from ->getName ( ));
4957 } elseif ($ from ->isTrait ()) {
50- $ class = new TraitType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName () ));
58+ $ class = new TraitType ($ from ->getName ( ));
5159 } else {
52- $ class = new ClassType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName ()) );
60+ $ class = new ClassType ($ from ->getShortName ());
5361 $ class ->setFinal ($ from ->isFinal () && $ class ->isClass ());
5462 $ class ->setAbstract ($ from ->isAbstract () && $ class ->isClass ());
5563 $ class ->setReadOnly (PHP_VERSION_ID >= 80200 && $ from ->isReadOnly ());
5664 }
5765
66+ $ class ->setNamespace (new PhpNamespace ($ from ->getNamespaceName ()));
67+ return $ class ;
68+ }
69+
70+
71+ /** @param \ReflectionClass<object> $from */
72+ private function setupInheritance (ClassLike $ class , \ReflectionClass $ from ): void
73+ {
5874 $ ifaces = $ from ->getInterfaceNames ();
5975 foreach ($ ifaces as $ iface ) {
6076 $ ifaces = array_filter ($ ifaces , fn (string $ item ): bool => !is_subclass_of ($ iface , $ item ));
6177 }
6278
6379 if ($ from ->isInterface ()) {
64- $ class ->setExtends ($ ifaces );
80+ $ class ->setExtends (array_values ( $ ifaces) );
6581 } elseif ($ ifaces ) {
66- $ ifaces = array_diff ($ ifaces , [$ enumIface ]);
67- $ class ->setImplements ($ ifaces );
82+ $ ifaces = array_diff ($ ifaces , [\BackedEnum::class, \UnitEnum::class ]);
83+ $ class ->setImplements (array_values ( $ ifaces) );
6884 }
6985
7086 $ class ->setComment (Helpers::unformatDocComment ((string ) $ from ->getDocComment ()));
7187 $ class ->setAttributes ($ this ->getAttributes ($ from ));
7288 if ($ from ->getParentClass ()) {
7389 $ class ->setExtends ($ from ->getParentClass ()->name );
74- $ class ->setImplements (array_diff ($ class ->getImplements (), $ from ->getParentClass ()->getInterfaceNames ()));
90+ $ class ->setImplements (array_values ( array_diff ($ class ->getImplements (), $ from ->getParentClass ()->getInterfaceNames () )));
7591 }
92+ }
93+
7694
95+ /** @param \ReflectionClass<object> $from */
96+ private function populateMembers (ClassLike $ class , \ReflectionClass $ from , bool $ withBodies ): void
97+ {
98+ // Properties
7799 $ props = [];
78100 foreach ($ from ->getProperties () as $ prop ) {
79101 $ declaringClass = Reflection::getPropertyDeclaringClass ($ prop );
@@ -84,8 +106,8 @@ public function fromClassReflection(
84106 && !$ class ->isEnum ()
85107 ) {
86108 $ props [] = $ p = $ this ->fromPropertyReflection ($ prop );
87- if ($ withBodies ) {
88- $ hookBodies ??= $ this ->getExtractor ($ declaringClass -> getFileName () )->extractPropertyHookBodies ($ declaringClass ->name );
109+ if ($ withBodies && ( $ file = $ declaringClass -> getFileName ()) ) {
110+ $ hookBodies ??= $ this ->getExtractor ($ file )->extractPropertyHookBodies ($ declaringClass ->name );
89111 foreach ($ hookBodies [$ prop ->getName ()] ?? [] as $ hookType => [$ body , $ short ]) {
90112 $ p ->getHook ($ hookType )->setBody ($ body , short: $ short );
91113 }
@@ -97,19 +119,20 @@ public function fromClassReflection(
97119 $ class ->setProperties ($ props );
98120 }
99121
122+ // Methods and trait resolutions
100123 $ methods = $ resolutions = [];
101124 foreach ($ from ->getMethods () as $ method ) {
102125 $ declaringMethod = Reflection::getMethodDeclaringMethod ($ method );
103126 $ declaringClass = $ declaringMethod ->getDeclaringClass ();
104127
105128 if (
106129 $ declaringClass ->name === $ from ->name
107- && (!$ enumIface || !method_exists ($ enumIface , $ method ->name ))
130+ && (!$ from instanceof \ReflectionEnum || !method_exists ($ from -> isBacked () ? \BackedEnum::class : \UnitEnum::class , $ method ->name ))
108131 ) {
109132 $ methods [] = $ m = $ this ->fromMethodReflection ($ method );
110- if ($ withBodies ) {
133+ if ($ withBodies && ( $ file = $ declaringClass -> getFileName ()) ) {
111134 $ bodies = &$ this ->bodyCache [$ declaringClass ->name ];
112- $ bodies ??= $ this ->getExtractor ($ declaringClass -> getFileName () )->extractMethodBodies ($ declaringClass ->name );
135+ $ bodies ??= $ this ->getExtractor ($ file )->extractMethodBodies ($ declaringClass ->name );
113136 if (isset ($ bodies [$ declaringMethod ->name ])) {
114137 $ m ->setBody ($ bodies [$ declaringMethod ->name ]);
115138 }
@@ -127,6 +150,7 @@ public function fromClassReflection(
127150
128151 $ class ->setMethods ($ methods );
129152
153+ // Traits
130154 foreach ($ from ->getTraitNames () as $ trait ) {
131155 $ trait = $ class ->addTrait ($ trait );
132156 foreach ($ resolutions as $ resolution ) {
@@ -135,9 +159,10 @@ public function fromClassReflection(
135159 $ resolutions = [];
136160 }
137161
162+ // Constants and enum cases
138163 $ consts = $ cases = [];
139164 foreach ($ from ->getReflectionConstants () as $ const ) {
140- if ($ class -> isEnum () && $ from ->hasCase ($ const ->name )) {
165+ if ($ from instanceof \ReflectionEnum && $ from ->hasCase ($ const ->name )) {
141166 $ cases [] = $ this ->fromCaseReflection ($ const );
142167 } elseif ($ const ->getDeclaringClass ()->name === $ from ->name ) {
143168 $ consts [] = $ this ->fromConstantReflection ($ const );
@@ -150,8 +175,6 @@ public function fromClassReflection(
150175 if ($ cases ) {
151176 $ class ->setCases ($ cases );
152177 }
153-
154- return $ class ;
155178 }
156179
157180
@@ -188,11 +211,11 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody
188211 $ function ->setReturnType ((string ) $ from ->getReturnType ());
189212
190213 if ($ withBody ) {
191- if ($ from ->isClosure () || $ from ->isInternal ()) {
214+ if ($ from ->isClosure () || $ from ->isInternal () || !( $ file = $ from -> getFileName ()) ) {
192215 throw new Nette \NotSupportedException ('The $withBody parameter cannot be used for closures or internal functions. ' );
193216 }
194217
195- $ function ->setBody ($ this ->getExtractor ($ from -> getFileName () )->extractFunctionBody ($ from ->name ));
218+ $ function ->setBody ($ this ->getExtractor ($ file )->extractFunctionBody ($ from ->name ));
196219 }
197220
198221 return $ function ;
0 commit comments