Skip to content

Commit 372fdcb

Browse files
committed
Factory::fromClassReflection() added option to materialize traits or not [Closes #89]
1 parent 479c2a7 commit 372fdcb

7 files changed

+219
-14
lines changed

src/PhpGenerator/ClassType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ public static function enum(string $name = null, PhpNamespace $namespace = null)
9999
/**
100100
* @param string|object $class
101101
*/
102-
public static function from($class): self
102+
public static function from($class, bool $withBodies = false, bool $materializeTraits = true): self
103103
{
104-
return (new Factory)->fromClassReflection(new \ReflectionClass($class));
104+
return (new Factory)->fromClassReflection(new \ReflectionClass($class), $withBodies, $materializeTraits);
105105
}
106106

107107

src/PhpGenerator/Factory.php

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Nette\PhpGenerator;
1111

1212
use Nette;
13+
use Nette\Utils\Reflection;
1314

1415

1516
/**
@@ -23,8 +24,11 @@ final class Factory
2324
private $extractorCache = [];
2425

2526

26-
public function fromClassReflection(\ReflectionClass $from, bool $withBodies = false): ClassType
27-
{
27+
public function fromClassReflection(
28+
\ReflectionClass $from,
29+
bool $withBodies = false,
30+
bool $materializeTraits = true
31+
): ClassType {
2832
if ($withBodies && $from->isAnonymous()) {
2933
throw new Nette\NotSupportedException('The $withBodies parameter cannot be used for anonymous functions.');
3034
}
@@ -66,8 +70,12 @@ public function fromClassReflection(\ReflectionClass $from, bool $withBodies = f
6670

6771
$props = [];
6872
foreach ($from->getProperties() as $prop) {
73+
$declaringClass = $materializeTraits
74+
? $prop->getDeclaringClass()
75+
: Reflection::getPropertyDeclaringClass($prop);
76+
6977
if ($prop->isDefault()
70-
&& $prop->getDeclaringClass()->name === $from->name
78+
&& $declaringClass->name === $from->name
7179
&& (PHP_VERSION_ID < 80000 || !$prop->isPromoted())
7280
&& !$class->isEnum()
7381
) {
@@ -78,24 +86,32 @@ public function fromClassReflection(\ReflectionClass $from, bool $withBodies = f
7886

7987
$methods = [];
8088
foreach ($from->getMethods() as $method) {
89+
$realMethod = Reflection::getMethodDeclaringMethod($method);
90+
$declaringClass = ($materializeTraits ? $method : $realMethod)->getDeclaringClass();
91+
8192
if (
82-
$method->getDeclaringClass()->name === $from->name
93+
$declaringClass->name === $from->name
8394
&& (!$enumIface || !method_exists($enumIface, $method->name))
8495
) {
8596
$methods[] = $m = $this->fromMethodReflection($method);
8697
if ($withBodies) {
87-
$srcMethod = Nette\Utils\Reflection::getMethodDeclaringMethod($method);
88-
$srcClass = $srcMethod->getDeclaringClass();
89-
$bodies = &$this->bodyCache[$srcClass->name];
90-
$bodies = $bodies ?? $this->getExtractor($srcClass)->extractMethodBodies($srcClass->name);
91-
if (isset($bodies[$srcMethod->name])) {
92-
$m->setBody($bodies[$srcMethod->name]);
98+
$realMethodClass = $realMethod->getDeclaringClass();
99+
$bodies = &$this->bodyCache[$realMethodClass->name];
100+
$bodies = $bodies ?? $this->getExtractor($realMethodClass)->extractMethodBodies($realMethodClass->name);
101+
if (isset($bodies[$realMethod->name])) {
102+
$m->setBody($bodies[$realMethod->name]);
93103
}
94104
}
95105
}
96106
}
97107
$class->setMethods($methods);
98108

109+
if (!$materializeTraits) {
110+
foreach ($from->getTraitNames() as $trait) {
111+
$class->addTrait($trait);
112+
}
113+
}
114+
99115
$consts = $cases = [];
100116
foreach ($from->getReflectionConstants() as $const) {
101117
if ($class->isEnum() && $from->hasCase($const->name)) {

tests/PhpGenerator/ClassType.from.trait.phpt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,25 @@ $res = array_map(function ($class) {
2424
return ClassType::from($class);
2525
}, $classes);
2626

27-
sameFile(__DIR__ . '/expected/ClassType.from.trait.expect', implode("\n", $res));
27+
sameFile(__DIR__ . '/expected/ClassType.from.trait-materialize.expect', implode("\n", $res));
2828

2929

3030
$res = array_map(function ($class) {
3131
return ClassType::withBodiesFrom($class);
3232
}, $classes);
3333

34-
sameFile(__DIR__ . '/expected/ClassType.from.trait.bodies.expect', implode("\n", $res));
34+
sameFile(__DIR__ . '/expected/ClassType.from.trait-materialize.bodies.expect', implode("\n", $res));
35+
36+
37+
$res = array_map(function ($class) {
38+
return ClassType::from($class, /*withBodies:*/ false, /*materializeTraits:*/ false);
39+
}, $classes);
40+
41+
sameFile(__DIR__ . '/expected/ClassType.from.trait-use.expect', implode("\n", $res));
42+
43+
44+
$res = array_map(function ($class) {
45+
return ClassType::from($class, /*withBodies:*/ true, /*materializeTraits:*/ false);
46+
}, $classes);
47+
48+
sameFile(__DIR__ . '/expected/ClassType.from.trait-use.bodies.expect', implode("\n", $res));
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Trait1
3+
*/
4+
trait Trait1
5+
{
6+
public static $s1;
7+
public $x1;
8+
9+
10+
public function f1()
11+
{
12+
echo 'Trait1::f1';
13+
}
14+
}
15+
16+
trait Trait1b
17+
{
18+
public function f1()
19+
{
20+
echo 'Trait1b::f1';
21+
}
22+
}
23+
24+
trait Trait2
25+
{
26+
use Trait1;
27+
28+
protected $x2;
29+
30+
31+
public function f2()
32+
{
33+
echo 'Trait2::f2';
34+
}
35+
}
36+
37+
class ParentClass
38+
{
39+
public $x1;
40+
41+
42+
public function f1()
43+
{
44+
echo 'ParentClass::f1';
45+
}
46+
}
47+
48+
class Class1 extends ParentClass
49+
{
50+
use Trait2;
51+
}
52+
53+
class Class2 extends ParentClass
54+
{
55+
use Trait2;
56+
57+
public function f1()
58+
{
59+
echo 'Class2::f1';
60+
}
61+
}
62+
63+
class Class3 extends ParentClass
64+
{
65+
use Trait2;
66+
67+
/** info */
68+
public $x1;
69+
70+
71+
public function f1()
72+
{
73+
echo 'Class3::f1';
74+
}
75+
}
76+
77+
class Class4 extends ParentClass
78+
{
79+
use Trait2;
80+
81+
public function aliased()
82+
{
83+
echo 'Class4::aliased';
84+
}
85+
}
86+
87+
class Class5
88+
{
89+
use Trait1;
90+
use Trait1b;
91+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Trait1
3+
*/
4+
trait Trait1
5+
{
6+
public static $s1;
7+
public $x1;
8+
9+
10+
public function f1()
11+
{
12+
}
13+
}
14+
15+
trait Trait1b
16+
{
17+
public function f1()
18+
{
19+
}
20+
}
21+
22+
trait Trait2
23+
{
24+
use Trait1;
25+
26+
protected $x2;
27+
28+
29+
public function f2()
30+
{
31+
}
32+
}
33+
34+
class ParentClass
35+
{
36+
public $x1;
37+
38+
39+
public function f1()
40+
{
41+
}
42+
}
43+
44+
class Class1 extends ParentClass
45+
{
46+
use Trait2;
47+
}
48+
49+
class Class2 extends ParentClass
50+
{
51+
use Trait2;
52+
53+
public function f1()
54+
{
55+
}
56+
}
57+
58+
class Class3 extends ParentClass
59+
{
60+
use Trait2;
61+
62+
/** info */
63+
public $x1;
64+
65+
66+
public function f1()
67+
{
68+
}
69+
}
70+
71+
class Class4 extends ParentClass
72+
{
73+
use Trait2;
74+
75+
public function aliased()
76+
{
77+
}
78+
}
79+
80+
class Class5
81+
{
82+
use Trait1;
83+
use Trait1b;
84+
}

0 commit comments

Comments
 (0)