Skip to content

Commit 1962e53

Browse files
committed
ClassType: added inheritMethod() & inheritProperty()
1 parent 447dd6b commit 1962e53

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

src/PhpGenerator/ClassType.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,59 @@ public function addMember(Method|Property|Constant|TraitUse $member): static
212212
}
213213

214214

215+
/**
216+
* Inherits property from parent class.
217+
*/
218+
public function inheritProperty(string $name, bool $returnIfExists = false): Property
219+
{
220+
if (isset($this->properties[$name])) {
221+
return $returnIfExists
222+
? $this->properties[$name]
223+
: throw new Nette\InvalidStateException("Cannot inherit property '$name', because it already exists.");
224+
225+
} elseif (!$this->extends) {
226+
throw new Nette\InvalidStateException("Class '{$this->getName()}' has not setExtends() set.");
227+
}
228+
229+
try {
230+
$rp = new \ReflectionProperty($this->extends, $name);
231+
} catch (\ReflectionException) {
232+
throw new Nette\InvalidStateException("Property '$name' has not been found in ancestor {$this->extends}");
233+
}
234+
235+
return $this->properties[$name] = (new Factory)->fromPropertyReflection($rp);
236+
}
237+
238+
239+
/**
240+
* Inherits method from parent class or interface.
241+
*/
242+
public function inheritMethod(string $name, bool $returnIfExists = false): Method
243+
{
244+
$lower = strtolower($name);
245+
$parents = [...(array) $this->extends, ...$this->implements];
246+
if (isset($this->methods[$lower])) {
247+
return $returnIfExists
248+
? $this->methods[$lower]
249+
: throw new Nette\InvalidStateException("Cannot inherit method '$name', because it already exists.");
250+
251+
} elseif (!$parents) {
252+
throw new Nette\InvalidStateException("Class '{$this->getName()}' has neither setExtends() nor setImplements() set.");
253+
}
254+
255+
foreach ($parents as $parent) {
256+
try {
257+
$rm = new \ReflectionMethod($parent, $name);
258+
} catch (\ReflectionException) {
259+
continue;
260+
}
261+
return $this->methods[$lower] = (new Factory)->fromMethodReflection($rm);
262+
}
263+
264+
throw new Nette\InvalidStateException("Method '$name' has not been found in any ancestor: " . implode(', ', $parents));
265+
}
266+
267+
215268
/** @throws Nette\InvalidStateException */
216269
public function validate(): void
217270
{
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Tester\Assert;
6+
7+
require __DIR__ . '/../bootstrap.php';
8+
9+
10+
class Foo
11+
{
12+
public function bar(int $a, ...$b): void
13+
{
14+
}
15+
}
16+
17+
18+
// missing parent
19+
$class = new Nette\PhpGenerator\ClassType('Test');
20+
Assert::exception(
21+
fn() => $class->inheritMethod('bar'),
22+
Nette\InvalidStateException::class,
23+
"Class 'Test' has neither setExtends() nor setImplements() set.",
24+
);
25+
26+
$class->setExtends('Unknown1');
27+
$class->addImplement('Unknown2');
28+
Assert::exception(
29+
fn() => $class->inheritMethod('bar'),
30+
Nette\InvalidStateException::class,
31+
"Method 'bar' has not been found in any ancestor: Unknown1, Unknown2",
32+
);
33+
34+
35+
// implement method
36+
$class = new Nette\PhpGenerator\ClassType('Test');
37+
$class->setExtends(Foo::class);
38+
$method = $class->inheritMethod('bar');
39+
Assert::match(<<<'XX'
40+
public function bar(int $a, ...$b): void
41+
{
42+
}
43+
44+
XX, (string) $method);
45+
46+
Assert::same($method, $class->inheritMethod('bar', returnIfExists: true));
47+
Assert::exception(
48+
fn() => $class->inheritMethod('bar', returnIfExists: false),
49+
Nette\InvalidStateException::class,
50+
"Cannot inherit method 'bar', because it already exists.",
51+
);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Tester\Assert;
6+
7+
require __DIR__ . '/../bootstrap.php';
8+
9+
10+
class Foo
11+
{
12+
public array $bar = [123];
13+
}
14+
15+
16+
// missing parent
17+
$class = new Nette\PhpGenerator\ClassType('Test');
18+
Assert::exception(
19+
fn() => $class->inheritProperty('bar'),
20+
Nette\InvalidStateException::class,
21+
"Class 'Test' has not setExtends() set.",
22+
);
23+
24+
$class->setExtends('Unknown');
25+
Assert::exception(
26+
fn() => $class->inheritProperty('bar'),
27+
Nette\InvalidStateException::class,
28+
"Property 'bar' has not been found in ancestor Unknown",
29+
);
30+
31+
32+
// implement property
33+
$class = new Nette\PhpGenerator\ClassType('Test');
34+
$class->setExtends(Foo::class);
35+
$prop = $class->inheritProperty('bar');
36+
Assert::match(<<<'XX'
37+
class Test extends Foo
38+
{
39+
public array $bar = [123];
40+
}
41+
42+
XX, (string) $class);
43+
44+
Assert::same($prop, $class->inheritProperty('bar', returnIfExists: true));
45+
Assert::exception(
46+
fn() => $class->inheritProperty('bar', returnIfExists: false),
47+
Nette\InvalidStateException::class,
48+
"Cannot inherit property 'bar', because it already exists.",
49+
);

0 commit comments

Comments
 (0)