Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 09d7a2b

Browse files
committed
ClassManipulator::implement() can implement abstract classes
1 parent 4628dec commit 09d7a2b

File tree

3 files changed

+70
-15
lines changed

3 files changed

+70
-15
lines changed

‎readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ $property = $manipulator->inheritProperty('foo');
902902
$property->setValue('new value');
903903
```
904904
905-
The `implement()` method automatically implements all methods from the given interface in your class:
905+
The `implement()` method automatically implements all methods and properties from the given interface or abstract class:
906906
907907
```php
908908
$manipulator->implement(SomeInterface::class);

‎src/PhpGenerator/ClassManipulator.php

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,32 +68,44 @@ public function inheritMethod(string $name, bool $returnIfExists = false): Metho
6868
} catch (\ReflectionException) {
6969
continue;
7070
}
71-
$method = (new Factory)->fromMethodReflection($rm);
72-
$this->class->addMember($method);
73-
return $method;
71+
return $this->implementMethod($rm);
7472
}
7573

7674
throw new Nette\InvalidStateException("Method '$name' has not been found in any ancestor: " . implode(', ', $parents));
7775
}
7876

7977

8078
/**
81-
* Implements all methods from the given interface.
79+
* Implements all methods from the given interface or abstract class.
8280
*/
8381
public function implement(string $name): void
8482
{
8583
$definition = new \ReflectionClass($name);
86-
if (!$definition->isInterface()) {
87-
throw new Nette\InvalidArgumentException("Class '$name' is not an interface.");
84+
if ($definition->isInterface()) {
85+
$this->class->addImplement($name);
86+
} elseif ($definition->isAbstract()) {
87+
$this->class->setExtends($name);
88+
} else {
89+
throw new Nette\InvalidArgumentException("'$name' is not an interface or abstract class.");
8890
}
8991

90-
$this->class->addImplement($name);
9192
foreach ($definition->getMethods() as $method) {
92-
$this->inheritMethod($method->getName(), returnIfExists: true);
93+
if (!$this->class->hasMethod($method->getName()) && $method->isAbstract()) {
94+
$this->implementMethod($method);
95+
}
9396
}
9497
}
9598

9699

100+
private function implementMethod(\ReflectionMethod $rm): Method
101+
{
102+
$method = (new Factory)->fromMethodReflection($rm);
103+
$method->setAbstract(false);
104+
$this->class->addMember($method);
105+
return $method;
106+
}
107+
108+
97109
/** @deprecated use implement() */
98110
public function implementInterface(string $interfaceName): void
99111
{

‎tests/PhpGenerator/ClassManipulator.implement.phpt

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,64 @@ use Tester\Assert;
99
require __DIR__ . '/../bootstrap.php';
1010

1111

12-
interface TestInterface
12+
interface ParentInterface
1313
{
14-
public function testMethod();
14+
public function interfaceMethod();
1515
}
1616

17+
interface TestInterface extends ParentInterface
18+
{
19+
}
20+
21+
abstract class ParentAbstract
22+
{
23+
abstract public function abstractMethod();
24+
25+
26+
public function concreteMethod()
27+
{
28+
}
29+
}
30+
31+
abstract class TestAbstract extends ParentAbstract
32+
{
33+
}
34+
35+
1736
$class = new ClassType('TestClass');
1837
$manipulator = new ClassManipulator($class);
1938

20-
// Test valid interface implementation
39+
// Test interface implementation
2140
$manipulator->implement(TestInterface::class);
22-
Assert::true(in_array(TestInterface::class, $class->getImplements(), true));
23-
Assert::true($class->hasMethod('testMethod'));
41+
Assert::match(<<<'XX'
42+
class TestClass implements TestInterface
43+
{
44+
function interfaceMethod()
45+
{
46+
}
47+
}
48+
49+
XX, (string) $class);
50+
51+
52+
// Test abstract class extension
53+
$class = new ClassType('TestClass');
54+
$manipulator = new ClassManipulator($class);
55+
$manipulator->implement(TestAbstract::class);
56+
Assert::match(<<<'XX'
57+
class TestClass extends TestAbstract
58+
{
59+
public function abstractMethod()
60+
{
61+
}
62+
}
63+
64+
XX, (string) $class);
65+
2466

25-
// Test exception for non-interface
67+
// Test exception for regular class
2668
Assert::exception(
2769
fn() => $manipulator->implement(stdClass::class),
2870
InvalidArgumentException::class,
71+
"'stdClass' is not an interface or abstract class.",
2972
);

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /