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 4280604

Browse files
xHeavendg
authored andcommitted
Factory::fromClassReflection() extracts property hook bodies (#172)
1 parent ff08574 commit 4280604

File tree

5 files changed

+188
-1
lines changed

5 files changed

+188
-1
lines changed

‎src/PhpGenerator/Extractor.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,36 @@ public function extractMethodBodies(string $className): array
7979
}
8080

8181

82+
/** @return array<string, array<string, array{string, bool}>> */
83+
public function extractPropertyHookBodies(string $className): array
84+
{
85+
if (!class_exists(Node\PropertyHook::class)) {
86+
return [];
87+
}
88+
89+
$nodeFinder = new NodeFinder;
90+
$classNode = $nodeFinder->findFirst(
91+
$this->statements,
92+
fn(Node $node) => $node instanceof Node\Stmt\ClassLike && $node->namespacedName->toString() === $className,
93+
);
94+
95+
$res = [];
96+
foreach ($nodeFinder->findInstanceOf($classNode, Node\Stmt\Property::class) as $propertyNode) {
97+
foreach ($propertyNode->props as $propNode) {
98+
$propName = $propNode->name->toString();
99+
foreach ($propertyNode->hooks as $hookNode) {
100+
$body = $hookNode->body;
101+
if ($body !== null) {
102+
$contents = $this->getReformattedContents(is_array($body) ? $body : [$body], 3);
103+
$res[$propName][$hookNode->name->toString()] = [$contents, !is_array($body)];
104+
}
105+
}
106+
}
107+
}
108+
return $res;
109+
}
110+
111+
82112
public function extractFunctionBody(string $name): ?string
83113
{
84114
$functionNode = (new NodeFinder)->findFirst(
@@ -94,6 +124,9 @@ public function extractFunctionBody(string $name): ?string
94124
/** @param Node[] $nodes */
95125
private function getReformattedContents(array $nodes, int $level): string
96126
{
127+
if (!$nodes) {
128+
return '';
129+
}
97130
$body = $this->getNodeContents(...$nodes);
98131
$body = $this->performReplacements($body, $this->prepareReplacements($nodes, $level));
99132
return Helpers::unindent($body, $level);

‎src/PhpGenerator/Factory.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ public function fromClassReflection(
8181
&& !$prop->isPromoted()
8282
&& !$class->isEnum()
8383
) {
84-
$props[] = $this->fromPropertyReflection($prop);
84+
$props[] = $p = $this->fromPropertyReflection($prop);
85+
if ($withBodies) {
86+
$hookBodies ??= $this->getExtractor($declaringClass->getFileName())->extractPropertyHookBodies($declaringClass->name);
87+
foreach ($hookBodies[$prop->getName()] ?? [] as $hookType => [$body, $short]) {
88+
$p->getHook($hookType)->setBody($body, short: $short);
89+
}
90+
}
8591
}
8692
}
8793

‎tests/PhpGenerator/ClassType.from.bodies.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@ Assert::exception(
2929

3030
$res = ClassType::from(Abc\Class7::class, withBodies: true);
3131
sameFile(__DIR__ . '/expected/ClassType.from.bodies.expect', (string) $res);
32+
33+
34+
if (PHP_VERSION_ID >= 80400) {
35+
require __DIR__ . '/fixtures/classes.84.php';
36+
$res = [];
37+
$res[] = ClassType::from(Abc\PropertyHookSignatures::class, withBodies: true);
38+
$res[] = ClassType::from(Abc\AbstractHookSignatures::class, withBodies: true);
39+
$res[] = ClassType::from(Abc\PropertyHookSignaturesChild::class, withBodies: true);
40+
sameFile(__DIR__ . '/expected/ClassType.from.bodies.84.expect', implode("\n", $res));
41+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\PhpGenerator\Extractor;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
$extractor = new Extractor(<<<'XX'
12+
<?php
13+
namespace NS;
14+
15+
abstract class Foo
16+
{
17+
public string $short {
18+
get => 'x';
19+
}
20+
21+
public string $full {
22+
get {
23+
if (true) {
24+
return 'x';
25+
} else {
26+
return 'y';
27+
}
28+
}
29+
}
30+
31+
public string $empty {
32+
set { }
33+
}
34+
35+
abstract public string $abstract { get; }
36+
}
37+
38+
XX);
39+
40+
$bodies = $extractor->extractPropertyHookBodies('NS\Undefined');
41+
Assert::same([], $bodies);
42+
43+
$bodies = $extractor->extractPropertyHookBodies('NS\Foo');
44+
Assert::same([
45+
'short' => ['get' => ["'x'", true]],
46+
'full' => [
47+
'get' => ["if (true) {\n return 'x';\n} else {\n return 'y';\n}", false],
48+
],
49+
'empty' => ['set' => ['', false]],
50+
], $bodies);
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
class PropertyHookSignatures
2+
{
3+
public string $basic {
4+
get => 'x';
5+
}
6+
7+
public string $fullGet {
8+
get {
9+
return 'x';
10+
}
11+
}
12+
13+
protected string $refGet {
14+
&get {
15+
return 'x';
16+
}
17+
}
18+
19+
protected string $finalGet {
20+
final get => 'x';
21+
}
22+
23+
public string $basicSet {
24+
set => 'x';
25+
}
26+
27+
public string $fullSet {
28+
set {
29+
}
30+
}
31+
32+
public string $setWithParam {
33+
set(string $foo) {
34+
}
35+
}
36+
37+
public string $setWithParam2 {
38+
set(string|int $value) => '';
39+
}
40+
41+
public string $finalSet {
42+
final set {
43+
}
44+
}
45+
46+
public string $combined {
47+
set {
48+
}
49+
get => 'x';
50+
}
51+
52+
final public string $combinedFinal {
53+
/** comment set */
54+
#[Set]
55+
set {
56+
}
57+
/** comment get */
58+
#[Get]
59+
get => 'x';
60+
}
61+
62+
public string $virtualProp {
63+
set {
64+
}
65+
&get => 'x';
66+
}
67+
}
68+
69+
abstract class AbstractHookSignatures
70+
{
71+
abstract public string $abstractGet { get; }
72+
abstract protected string $abstractSet { set; }
73+
abstract public string $abstractBoth { set; get; }
74+
75+
abstract public string $mixedGet {
76+
set => 'x';
77+
get;
78+
}
79+
80+
abstract public string $mixedSet {
81+
set;
82+
get => 'x';
83+
}
84+
}
85+
86+
class PropertyHookSignaturesChild extends PropertyHookSignatures
87+
{
88+
}

0 commit comments

Comments
(0)

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