Skip to content

Commit 8bbd422

Browse files
committed
Corresponds to the method of defining field variables with constructor arguments introduced in php8.
1 parent 51d90d3 commit 8bbd422

File tree

8 files changed

+140
-27
lines changed

8 files changed

+140
-27
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# CHANGELOG
22

3+
### Features
4+
5+
* Corresponds to the method of defining field variables with constructor arguments introduced in php8.
6+
7+
38
## v1.0.0 (2023-04-06)
49

510

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Smeghead\PhpClassDiagram\Php\Finder;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Param;
9+
use PhpParser\Node\Stmt\Class_;
10+
use PhpParser\Node\Stmt\ClassLike;
11+
use PhpParser\Node\Stmt\ClassMethod;
12+
use PhpParser\NodeFinder;
13+
14+
class FindConstructerProperties
15+
{
16+
private array $properties = [];
17+
private ?ClassMethod $constructer;
18+
19+
public function __construct(ClassLike $class)
20+
{
21+
$finder = new NodeFinder();
22+
/** @var ClassMethod $constructer */
23+
$constructer = $finder->findFirst($class, function (Node $node) {
24+
return $node instanceof ClassMethod && $node->name->toString() === '__construct';
25+
});
26+
if ($constructer === null) {
27+
return;
28+
}
29+
$this->constructer = $constructer;
30+
foreach ($constructer->getParams() as $p) {
31+
if ($p->flags & Class_::MODIFIER_PUBLIC) {
32+
$this->properties[] = $p;
33+
} else if ($p->flags & Class_::MODIFIER_PRIVATE) {
34+
$this->properties[] = $p;
35+
} else if ($p->flags & Class_::MODIFIER_PROTECTED) {
36+
$this->properties[] = $p;
37+
}
38+
}
39+
}
40+
41+
/**
42+
* @return Param[]
43+
*/
44+
public function getProperties(): array
45+
{
46+
return $this->properties;
47+
}
48+
49+
public function getConstructer(): ?ClassMethod
50+
{
51+
return $this->constructer;
52+
}
53+
}

src/Php/PhpAccessModifier.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
namespace Smeghead\PhpClassDiagram\Php;
66

7+
use PhpParser\Node\Param;
78
use PhpParser\Node\Stmt\{
9+
Class_,
810
ClassConst,
911
ClassMethod,
1012
Property,
@@ -19,14 +21,20 @@ class PhpAccessModifier
1921
private bool $final = false;
2022
private bool $static = false;
2123

22-
public function __construct(ClassConst|Property|ClassMethod $stmt)
24+
public function __construct(ClassConst|Property|ClassMethod|Param $stmt)
2325
{
24-
$this->public = $stmt->isPublic();
25-
$this->protected = $stmt->isProtected();
26-
$this->private = $stmt->isPrivate();
27-
$this->static = $stmt->isStatic();
28-
if ($stmt instanceof ClassMethod) {
29-
$this->abstract = $stmt->isAbstract();
26+
if ($stmt instanceof Param) {
27+
$this->public = boolval($stmt->flags & Class_::MODIFIER_PUBLIC);
28+
$this->protected = boolval($stmt->flags & Class_::MODIFIER_PROTECTED);
29+
$this->private = boolval($stmt->flags & Class_::MODIFIER_PRIVATE);
30+
} else {
31+
$this->public = $stmt->isPublic();
32+
$this->protected = $stmt->isProtected();
33+
$this->private = $stmt->isPrivate();
34+
$this->static = $stmt->isStatic();
35+
if ($stmt instanceof ClassMethod) {
36+
$this->abstract = $stmt->isAbstract();
37+
}
3038
}
3139
}
3240

src/Php/PhpClass.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Smeghead\PhpClassDiagram\Php;
66

7+
use PhpParser\NodeFinder;
8+
use PhpParser\Node;
79
use PhpParser\Node\{
810
NullableType,
911
Identifier,
@@ -23,6 +25,7 @@
2325
Use_,
2426
};
2527
use Smeghead\PhpClassDiagram\Php\Doc\PhpDocComment;
28+
use Smeghead\PhpClassDiagram\Php\Finder\FindConstructerProperties;
2629

2730
class PhpClass
2831
{
@@ -98,7 +101,12 @@ public function getProperties(): array
98101
$properties = $this->getPropertiesFromSyntax();
99102
$props = [];
100103
foreach ($properties as $p) {
101-
$props[] = new PhpProperty($p, $this);
104+
$props[] = PhpProperty::buildByProperty($p, $this);
105+
}
106+
107+
$finder = new FindConstructerProperties($this->syntax);
108+
foreach ($finder->getProperties() as $param) {
109+
$props[] = PhpProperty::buildByParam($param, $finder->getConstructer(), $this);
102110
}
103111
return $props;
104112
}
@@ -234,7 +242,7 @@ public function getExtends(): array
234242
*/
235243
public function getEnumCases(): array
236244
{
237-
if ( ! $this->syntax instanceof Enum_) {
245+
if (!$this->syntax instanceof Enum_) {
238246
return [];
239247
}
240248
$cases = [];
@@ -246,7 +254,8 @@ public function getEnumCases(): array
246254
return $cases;
247255
}
248256

249-
public function getDescription(): string {
257+
public function getDescription(): string
258+
{
250259
$doc = new PhpDocComment($this->syntax);
251260
return $doc->getDescription();
252261
}

src/Php/PhpProperty.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
namespace Smeghead\PhpClassDiagram\Php;
66

7+
use PhpParser\Node\Param;
78
use PhpParser\Node\Stmt\{
9+
ClassMethod,
810
Property,
911
};
1012

@@ -14,11 +16,26 @@ class PhpProperty
1416
private PhpTypeExpression $type;
1517
private PhpAccessModifier $accessModifier;
1618

17-
public function __construct(Property $p, PhpClass $class)
19+
private function __construct()
1820
{
19-
$this->name = $p->props[0]->name->toString();
20-
$this->type = PhpTypeExpression::buildByVar($p, $class->getNamespace(), $class->getUses());
21-
$this->accessModifier = new PhpAccessModifier($p);
21+
}
22+
23+
public static function buildByProperty(Property $p, PhpClass $class): self
24+
{
25+
$instance = new self();
26+
$instance->name = $p->props[0]->name->toString();
27+
$instance->type = PhpTypeExpression::buildByVar($p, $class->getNamespace(), $class->getUses());
28+
$instance->accessModifier = new PhpAccessModifier($p);
29+
return $instance;
30+
}
31+
32+
public static function buildByParam(Param $param, ClassMethod $method, PhpClass $class): self
33+
{
34+
$instance = new self();
35+
$instance->name = $param->var->name;
36+
$instance->type = PhpTypeExpression::buildByMethodParam($param, $class->getNamespace(), $method, $param->var->name, $class->getUses());
37+
$instance->accessModifier = new PhpAccessModifier($param);
38+
return $instance;
2239
}
2340

2441
public function getName(): string

src/Php/PhpTypeExpression.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpParser\Node\Name;
99
use PhpParser\Node\Name\FullyQualified;
1010
use PhpParser\Node\NullableType;
11+
use PhpParser\Node\Param;
1112
use PhpParser\Node\Stmt\ClassMethod;
1213
use PhpParser\Node\Stmt\Property;
1314
use PhpParser\Node\UnionType;

test/PhpReflectionTest.php

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,36 @@ public function testDump_Price(): void
6161
$this->assertSame([], $data->getProperties()[0]->getType()->getTypes()[0]->getNamespace(), 'namespace.');
6262
$this->assertSame(true, $data->getProperties()[0]->getAccessModifier()->isPrivate(), 'property price Modifiers.');
6363
}
64-
// public function testDump_php8_Price(): void {
65-
// $options = new Options([]);
66-
// $directory = sprintf('%s/php8', $this->fixtureDir);
67-
// $filename = sprintf('%s/php8/product/Price.php', $this->fixtureDir);
68-
// $classes = PhpReader::parseFile($directory, $filename, $options);
64+
public function testDump_php8_Price(): void
65+
{
66+
$options = new Options([]);
67+
$directory = sprintf('%s/php8', $this->fixtureDir);
68+
$filename = sprintf('%s/php8/product/Price.php', $this->fixtureDir);
69+
$classes = PhpReader::parseFile($directory, $filename, $options);
70+
71+
$data = $classes[0]->getInfo();
72+
$this->assertSame('Price', $data->getClassType()->getName(), 'class type name.');
73+
$this->assertSame(['hoge', 'fuga', 'product'], $data->getClassType()->getNamespace(), 'namespace name.');
74+
$this->assertSame('price8', $data->getProperties()[0]->getName(), 'property price.');
75+
$this->assertSame('int|float', $data->getProperties()[0]->getType()->getName(), 'property price type. php8 union type.');
76+
$this->assertSame([], $data->getProperties()[0]->getType()->getTypes()[0]->getNamespace(), 'namespace.');
77+
$this->assertSame(true, $data->getProperties()[0]->getAccessModifier()->isPrivate(), 'property price Modifiers.');
78+
}
79+
public function testDump_php8_constructer_properties(): void
80+
{
81+
$options = new Options([]);
82+
$directory = sprintf('%s/php8', $this->fixtureDir);
83+
$filename = sprintf('%s/php8/product/Price.php', $this->fixtureDir);
84+
$classes = PhpReader::parseFile($directory, $filename, $options);
6985

70-
// $data = $classes[0]->getInfo();
71-
// $this->assertSame('Price', $data->getClassType()->name, 'class type name.');
72-
// $this->assertSame(['hoge', 'fuga', 'product'], $data->getClassType()->getNamespace(), 'namespace name.');
73-
// $this->assertSame('price', $data->getProperties()[0]->name, 'property price.');
74-
// $this->assertSame('int|float', $data->getProperties()[0]->type->getName(), 'property price type. php8 union type.');
75-
// $this->assertSame(['hoge', 'fuga', 'product'], $data->getProperties()[0]->type->getNamespace(), 'namespace.');
76-
// $this->assertSame(true, $data->getProperties()[0]->accessModifier->private, 'property price Modifiers.');
77-
// }
86+
$data = $classes[0]->getInfo();
87+
$this->assertSame('Price', $data->getClassType()->getName(), 'class type name.');
88+
$this->assertSame(['hoge', 'fuga', 'product'], $data->getClassType()->getNamespace(), 'namespace name.');
89+
$this->assertSame('field1', $data->getProperties()[1]->getName(), 'property field1.');
90+
$this->assertSame('int', $data->getProperties()[1]->getType()->getName(), 'property field1 type. php8 union type.');
91+
$this->assertSame([], $data->getProperties()[1]->getType()->getTypes()[0]->getNamespace(), 'namespace.');
92+
$this->assertSame(true, $data->getProperties()[1]->getAccessModifier()->isPrivate(), 'property field1 Modifiers.');
93+
}
7894

7995
public function testDump_with_namespace(): void
8096
{

test/fixtures/php8/product/Price.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@
33

44
class Price {
55
private int|float $price8;
6+
7+
public function __construct(private int $field1)
8+
{
9+
}
610
}

0 commit comments

Comments
 (0)