@@ -35,43 +35,65 @@ public function fromClassReflection(
3535 throw new Nette \NotSupportedException ('The $withBodies parameter cannot be used for anonymous or internal classes or interfaces. ' );
3636 }
3737
38- $ enumIface = null ;
39- if ($ from ->isEnum ()) {
40- $ class = new EnumType ($ from ->getShortName (), new PhpNamespace ($ from ->getNamespaceName ()));
38+ $ class = $ this ->createClassObject ($ from );
39+ $ this ->setupInheritance ($ class , $ from );
40+ $ this ->populateMembers ($ class , $ from , $ withBodies );
41+ return $ class ;
42+ }
43+
44+
45+ /** @param \ReflectionClass<object> $from */
46+ private function createClassObject (\ReflectionClass &$ from ): ClassLike
47+ {
48+ if ($ from ->isAnonymous ()) {
49+ return new ClassType ;
50+ } elseif ($ from ->isEnum ()) {
4151 $ from = new \ReflectionEnum ($ from ->getName ());
42- $ enumIface = $ from ->isBacked () ? \BackedEnum::class : \UnitEnum::class;
43- } elseif ($ from ->isAnonymous ()) {
44- $ class = new ClassType ;
52+ $ class = new EnumType ($ from ->getName ());
4553 } elseif ($ from ->isInterface ()) {
46- $ class = new InterfaceType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName () ));
54+ $ class = new InterfaceType ($ from ->getName ( ));
4755 } elseif ($ from ->isTrait ()) {
48- $ class = new TraitType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName () ));
56+ $ class = new TraitType ($ from ->getName ( ));
4957 } else {
50- $ class = new ClassType ($ from ->getShortName (), new PhpNamespace ( $ from -> getNamespaceName ()) );
58+ $ class = new ClassType ($ from ->getShortName ());
5159 $ class ->setFinal ($ from ->isFinal () && $ class ->isClass ());
5260 $ class ->setAbstract ($ from ->isAbstract () && $ class ->isClass ());
5361 $ class ->setReadOnly (PHP_VERSION_ID >= 80200 && $ from ->isReadOnly ());
5462 }
5563
64+ $ class ->setNamespace (new PhpNamespace ($ from ->getNamespaceName ()));
65+ return $ class ;
66+ }
67+
68+
69+ /** @param \ReflectionClass<object> $from */
70+ private function setupInheritance (ClassLike $ class , \ReflectionClass $ from ): void
71+ {
5672 $ ifaces = $ from ->getInterfaceNames ();
5773 foreach ($ ifaces as $ iface ) {
5874 $ ifaces = array_filter ($ ifaces , fn (string $ item ): bool => !is_subclass_of ($ iface , $ item ));
5975 }
6076
6177 if ($ from ->isInterface ()) {
62- $ class ->setExtends ($ ifaces );
78+ $ class ->setExtends (array_values ( $ ifaces) );
6379 } elseif ($ ifaces ) {
64- $ ifaces = array_diff ($ ifaces , [$ enumIface ]);
65- $ class ->setImplements ($ ifaces );
80+ $ ifaces = array_diff ($ ifaces , [\BackedEnum::class, \UnitEnum::class ]);
81+ $ class ->setImplements (array_values ( $ ifaces) );
6682 }
6783
6884 $ class ->setComment (Helpers::unformatDocComment ((string ) $ from ->getDocComment ()));
6985 $ class ->setAttributes ($ this ->getAttributes ($ from ));
7086 if ($ from ->getParentClass ()) {
7187 $ class ->setExtends ($ from ->getParentClass ()->name );
72- $ class ->setImplements (array_diff ($ class ->getImplements (), $ from ->getParentClass ()->getInterfaceNames ()));
88+ $ class ->setImplements (array_values ( array_diff ($ class ->getImplements (), $ from ->getParentClass ()->getInterfaceNames () )));
7389 }
90+ }
91+
7492
93+ /** @param \ReflectionClass<object> $from */
94+ private function populateMembers (ClassLike $ class , \ReflectionClass $ from , bool $ withBodies ): void
95+ {
96+ // Properties
7597 $ props = [];
7698 foreach ($ from ->getProperties () as $ prop ) {
7799 $ declaringClass = Reflection::getPropertyDeclaringClass ($ prop );
@@ -82,8 +104,8 @@ public function fromClassReflection(
82104 && !$ class ->isEnum ()
83105 ) {
84106 $ props [] = $ p = $ this ->fromPropertyReflection ($ prop );
85- if ($ withBodies ) {
86- $ hookBodies ??= $ this ->getExtractor ($ declaringClass -> getFileName () )->extractPropertyHookBodies ($ declaringClass ->name );
107+ if ($ withBodies && ( $ file = $ declaringClass -> getFileName ()) ) {
108+ $ hookBodies ??= $ this ->getExtractor ($ file )->extractPropertyHookBodies ($ declaringClass ->name );
87109 foreach ($ hookBodies [$ prop ->getName ()] ?? [] as $ hookType => [$ body , $ short ]) {
88110 $ p ->getHook ($ hookType )->setBody ($ body , short: $ short );
89111 }
@@ -95,19 +117,20 @@ public function fromClassReflection(
95117 $ class ->setProperties ($ props );
96118 }
97119
120+ // Methods and trait resolutions
98121 $ methods = $ resolutions = [];
99122 foreach ($ from ->getMethods () as $ method ) {
100123 $ declaringMethod = Reflection::getMethodDeclaringMethod ($ method );
101124 $ declaringClass = $ declaringMethod ->getDeclaringClass ();
102125
103126 if (
104127 $ declaringClass ->name === $ from ->name
105- && (!$ enumIface || !method_exists ($ enumIface , $ method ->name ))
128+ && (!$ from instanceof \ReflectionEnum || !method_exists ($ from -> isBacked () ? \BackedEnum::class : \UnitEnum::class , $ method ->name ))
106129 ) {
107130 $ methods [] = $ m = $ this ->fromMethodReflection ($ method );
108- if ($ withBodies ) {
131+ if ($ withBodies && ( $ file = $ declaringClass -> getFileName ()) ) {
109132 $ bodies = &$ this ->bodyCache [$ declaringClass ->name ];
110- $ bodies ??= $ this ->getExtractor ($ declaringClass -> getFileName () )->extractMethodBodies ($ declaringClass ->name );
133+ $ bodies ??= $ this ->getExtractor ($ file )->extractMethodBodies ($ declaringClass ->name );
111134 if (isset ($ bodies [$ declaringMethod ->name ])) {
112135 $ m ->setBody ($ bodies [$ declaringMethod ->name ]);
113136 }
@@ -125,6 +148,7 @@ public function fromClassReflection(
125148
126149 $ class ->setMethods ($ methods );
127150
151+ // Traits
128152 foreach ($ from ->getTraitNames () as $ trait ) {
129153 $ trait = $ class ->addTrait ($ trait );
130154 foreach ($ resolutions as $ resolution ) {
@@ -133,9 +157,10 @@ public function fromClassReflection(
133157 $ resolutions = [];
134158 }
135159
160+ // Constants and enum cases
136161 $ consts = $ cases = [];
137162 foreach ($ from ->getReflectionConstants () as $ const ) {
138- if ($ class -> isEnum () && $ from ->hasCase ($ const ->name )) {
163+ if ($ from instanceof \ReflectionEnum && $ from ->hasCase ($ const ->name )) {
139164 $ cases [] = $ this ->fromCaseReflection ($ const );
140165 } elseif ($ const ->getDeclaringClass ()->name === $ from ->name ) {
141166 $ consts [] = $ this ->fromConstantReflection ($ const );
@@ -148,8 +173,6 @@ public function fromClassReflection(
148173 if ($ cases ) {
149174 $ class ->setCases ($ cases );
150175 }
151-
152- return $ class ;
153176 }
154177
155178
@@ -186,11 +209,11 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody
186209 $ function ->setReturnType ((string ) $ from ->getReturnType ());
187210
188211 if ($ withBody ) {
189- if ($ from ->isClosure () || $ from ->isInternal ()) {
212+ if ($ from ->isClosure () || $ from ->isInternal () || !( $ file = $ from -> getFileName ()) ) {
190213 throw new Nette \NotSupportedException ('The $withBody parameter cannot be used for closures or internal functions. ' );
191214 }
192215
193- $ function ->setBody ($ this ->getExtractor ($ from -> getFileName () )->extractFunctionBody ($ from ->name ));
216+ $ function ->setBody ($ this ->getExtractor ($ file )->extractFunctionBody ($ from ->name ));
194217 }
195218
196219 return $ function ;
0 commit comments