Skip to content

Commit 84ee524

Browse files
committed
Factory::fromClassReflection() refactoring
1 parent 47f2928 commit 84ee524

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
@@ -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

Comments
 (0)