Skip to content

Commit 1bb8070

Browse files
committed
Factory::fromClassReflection() refactoring
1 parent 4d91d21 commit 1bb8070

1 file changed

Lines changed: 46 additions & 23 deletions

File tree

src/PhpGenerator/Factory.php

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)