Skip to content

Commit d915b7f

Browse files
committed
Extractor: extracts native PHP values
1 parent a0f1aef commit d915b7f

File tree

2 files changed

+113
-10
lines changed

2 files changed

+113
-10
lines changed

Diff for: src/PhpGenerator/Extractor.php

+41-10
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ private function addPropertyToClass(ClassLike $class, Node\Stmt\Property $node):
292292
$prop->setVisibility($this->toVisibility($node->flags));
293293
$prop->setType($node->type ? $this->toPhp($node->type) : null);
294294
if ($item->default) {
295-
$prop->setValue($this->formatValue($item->default, 1));
295+
$prop->setValue($this->toValue($item->default));
296296
}
297297

298298
$prop->setReadOnly(method_exists($node, 'isReadonly') && $node->isReadonly());
@@ -315,7 +315,7 @@ private function addMethodToClass(ClassLike $class, Node\Stmt\ClassMethod $node)
315315
private function addConstantToClass(ClassLike $class, Node\Stmt\ClassConst $node): void
316316
{
317317
foreach ($node->consts as $item) {
318-
$const = $class->addConstant($item->name->toString(), $this->formatValue($item->value, 1));
318+
$const = $class->addConstant($item->name->toString(), $this->toValue($item->value));
319319
$const->setVisibility($this->toVisibility($node->flags));
320320
$const->setFinal(method_exists($node, 'isFinal') && $node->isFinal());
321321
$this->addCommentAndAttributes($const, $node);
@@ -328,7 +328,7 @@ private function addEnumCaseToClass(EnumType $class, Node\Stmt\EnumCase $node):
328328
$value = match (true) {
329329
$node->expr === null => null,
330330
$node->expr instanceof Node\Scalar\LNumber, $node->expr instanceof Node\Scalar\String_ => $node->expr->value,
331-
default => $this->formatValue($node->expr, 1),
331+
default => $this->toValue($node->expr),
332332
};
333333
$case = $class->addCase($node->name->toString(), $value);
334334
$this->addCommentAndAttributes($case, $node);
@@ -358,11 +358,10 @@ private function addCommentAndAttributes(
358358
foreach ($group->attrs as $attribute) {
359359
$args = [];
360360
foreach ($attribute->args as $arg) {
361-
$value = $this->formatValue($arg->value, 0);
362361
if ($arg->name) {
363-
$args[$arg->name->toString()] = $value;
362+
$args[$arg->name->toString()] = $this->toValue($arg->value);
364363
} else {
365-
$args[] = $value;
364+
$args[] = $this->toValue($arg->value);
366365
}
367366
}
368367

@@ -386,7 +385,7 @@ private function setupFunction(GlobalFunction|Method $function, Node\FunctionLik
386385
$param->setReference($item->byRef);
387386
$function->setVariadic($item->variadic);
388387
if ($item->default) {
389-
$param->setDefaultValue($this->formatValue($item->default, 2));
388+
$param->setDefaultValue($this->toValue($item->default));
390389
}
391390

392391
$this->addCommentAndAttributes($param, $item);
@@ -400,10 +399,42 @@ private function setupFunction(GlobalFunction|Method $function, Node\FunctionLik
400399
}
401400

402401

403-
private function formatValue(Node\Expr $value, int $level): Literal
402+
private function toValue(Node\Expr $node): mixed
404403
{
405-
$value = $this->getReformattedContents([$value], $level);
406-
return new Literal($value);
404+
if ($node instanceof Node\Expr\ConstFetch) {
405+
return match ($node->name->toLowerString()) {
406+
'null' => null,
407+
'true' => true,
408+
'false' => false,
409+
default => new Literal($this->getReformattedContents([$node], 0)),
410+
};
411+
} elseif ($node instanceof Node\Scalar\LNumber
412+
|| $node instanceof Node\Scalar\DNumber
413+
|| $node instanceof Node\Scalar\String_
414+
) {
415+
return $node->value;
416+
417+
} elseif ($node instanceof Node\Expr\Array_) {
418+
$res = [];
419+
foreach ($node->items as $item) {
420+
if ($item->unpack) {
421+
$res[] = new Literal($this->getReformattedContents([$item], 0));
422+
423+
} elseif ($item->key) {
424+
$key = $item->key instanceof Node\Identifier
425+
? $item->key->name
426+
: $this->toValue($item->key);
427+
$res[$key] = $this->toValue($item->value);
428+
429+
} else {
430+
$res[] = $this->toValue($item->value);
431+
}
432+
}
433+
return $res;
434+
435+
} else {
436+
return new Literal($this->getReformattedContents([$node], 0));
437+
}
407438
}
408439

409440

Diff for: tests/PhpGenerator/Extractor.extractAll.vars.phpt

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\PhpGenerator\Attribute;
6+
use Nette\PhpGenerator\Extractor;
7+
use Nette\PhpGenerator\Literal;
8+
use Tester\Assert;
9+
require __DIR__ . '/../bootstrap.php';
10+
11+
12+
$file = (new Extractor(<<<'XX'
13+
<?php
14+
15+
#[Attr(1, foo: 2, bar: new Attr(3))]
16+
class Class1
17+
{
18+
const Foo = [1];
19+
20+
public $null = null;
21+
public $scalar = [true, false, 1, 1.0, 'hello'];
22+
public $const = [PHP_VERSION, self::Foo];
23+
public $array = [1, 2, ['x' => [3]], ...self::Foo];
24+
public $concat = 'x' . 'y';
25+
public $math = 10 * 3;
26+
27+
public function foo($a = [1, 2, 3], $b = new stdClass(1, 2))
28+
{
29+
}
30+
}
31+
XX))->extractAll();
32+
33+
34+
$class = $file->getClasses()['Class1'];
35+
Assert::equal(
36+
new Attribute('Attr', [1, 'foo' => 2, 'bar' => new Literal('new /*(n*/\Attr(3)')]),
37+
$class->getAttributes()[0],
38+
);
39+
40+
Assert::same([1], $class->getConstant('Foo')->getValue());
41+
42+
Assert::same(null, $class->getProperty('null')->getValue());
43+
Assert::same(
44+
[true, false, 1, 1.0, 'hello'],
45+
$class->getProperty('scalar')->getValue(),
46+
);
47+
Assert::equal(
48+
[new Literal('/*(c*/\PHP_VERSION'), new Literal('self::Foo')],
49+
$class->getProperty('const')->getValue(),
50+
);
51+
Assert::equal(
52+
[1, 2, ['x' => [3]], new Literal('...self::Foo')],
53+
$class->getProperty('array')->getValue(),
54+
);
55+
Assert::equal(
56+
new Literal("'x' . 'y'"),
57+
$class->getProperty('concat')->getValue(),
58+
);
59+
Assert::equal(
60+
new Literal('10 * 3'),
61+
$class->getProperty('math')->getValue(),
62+
);
63+
64+
$method = $class->getMethod('foo');
65+
Assert::same(
66+
[1, 2, 3],
67+
$method->getParameter('a')->getDefaultValue(),
68+
);
69+
Assert::equal(
70+
new Literal('new /*(n*/\stdClass(1, 2)'),
71+
$method->getParameter('b')->getDefaultValue(),
72+
);

0 commit comments

Comments
 (0)