Skip to content

Commit 93e5914

Browse files
committed
Support for Typed Properties
So far this library did not support Typed Properties (a PHP 7.4 feature) and to stay relevant we wanted to introduce this. Nikita Popov's library made this rather simple but we did find an issues with Union types from that library. As such, in this change I included a new factory to convert the types of php parser into our own Type system.
1 parent 7e5d3e4 commit 93e5914

File tree

19 files changed

+270
-231
lines changed

19 files changed

+270
-231
lines changed

src/phpDocumentor/Reflection/Php/Factory/Argument.php

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,9 @@
1717
use phpDocumentor\Reflection\Php\ProjectFactoryStrategy;
1818
use phpDocumentor\Reflection\Php\StrategyContainer;
1919
use phpDocumentor\Reflection\PrettyPrinter;
20-
use phpDocumentor\Reflection\Type;
21-
use phpDocumentor\Reflection\TypeResolver;
2220
use phpDocumentor\Reflection\Types\Context;
2321
use PhpParser\Node\Expr\Variable;
24-
use PhpParser\Node\NullableType;
2522
use PhpParser\Node\Param;
26-
use PhpParser\Node\UnionType;
2723
use Webmozart\Assert\Assert;
2824

2925
/**
@@ -66,34 +62,13 @@ protected function doCreate($object, StrategyContainer $strategies, ?Context $co
6662
{
6763
Assert::isInstanceOf($object, Param::class);
6864
Assert::isInstanceOf($object->var, Variable::class);
69-
$default = null;
70-
if ($object->default !== null) {
71-
$default = $this->valueConverter->prettyPrintExpr($object->default);
72-
}
7365

74-
$type = null;
75-
if (!empty($object->type)) {
76-
$type = $this->createType($object);
77-
}
78-
79-
return new ArgumentDescriptor((string) $object->var->name, $type, $default, $object->byRef, $object->variadic);
80-
}
81-
82-
private function createType(Param $arg, ?Context $context = null) : ?Type
83-
{
84-
if ($arg->type === null) {
85-
return null;
86-
}
87-
88-
$typeResolver = new TypeResolver();
89-
if ($arg->type instanceof NullableType) {
90-
$typeString = '?' . $arg->type->type;
91-
} elseif ($arg->type instanceof UnionType) {
92-
$typeString = $arg->type->getType();
93-
} else {
94-
$typeString = $arg->type->toString();
95-
}
96-
97-
return $typeResolver->resolve($typeString, $context);
66+
return new ArgumentDescriptor(
67+
(string) $object->var->name,
68+
(new Type())->fromPhpParser($object->type),
69+
$object->default !== null ? $this->valueConverter->prettyPrintExpr($object->default) : null,
70+
$object->byRef,
71+
$object->variadic
72+
);
9873
}
9974
}

src/phpDocumentor/Reflection/Php/Factory/ClassConstant.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,10 @@ public function matches($object) : bool
5858
*/
5959
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
6060
{
61-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
62-
$default = null;
63-
if ($object->getValue() !== null) {
64-
$default = $this->valueConverter->prettyPrintExpr($object->getValue());
65-
}
66-
6761
return new ConstantElement(
6862
$object->getFqsen(),
69-
$docBlock,
70-
$default,
63+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
64+
$object->getValue() !== null ? $this->valueConverter->prettyPrintExpr($object->getValue()) : null,
7165
new Location($object->getLine()),
7266
$this->buildVisibility($object)
7367
);

src/phpDocumentor/Reflection/Php/Factory/Function_.php

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@
1717
use phpDocumentor\Reflection\Php\Function_ as FunctionDescriptor;
1818
use phpDocumentor\Reflection\Php\ProjectFactoryStrategy;
1919
use phpDocumentor\Reflection\Php\StrategyContainer;
20-
use phpDocumentor\Reflection\TypeResolver;
2120
use phpDocumentor\Reflection\Types\Context;
22-
use PhpParser\Node\NullableType;
2321
use PhpParser\Node\Stmt\Function_ as FunctionNode;
24-
use PhpParser\Node\UnionType;
2522

2623
/**
2724
* Strategy to convert Function_ to FunctionDescriptor
@@ -47,23 +44,12 @@ public function matches($object) : bool
4744
*/
4845
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
4946
{
50-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
51-
52-
$returnType = null;
53-
if ($object->getReturnType() !== null) {
54-
$typeResolver = new TypeResolver();
55-
if ($object->getReturnType() instanceof NullableType) {
56-
$typeString = '?' . $object->getReturnType()->type;
57-
} elseif ($object->getReturnType() instanceof UnionType) {
58-
$typeString = $object->getReturnType()->getType();
59-
} else {
60-
$typeString = $object->getReturnType()->toString();
61-
}
62-
63-
$returnType = $typeResolver->resolve($typeString, $context);
64-
}
65-
66-
$function = new FunctionDescriptor($object->fqsen, $docBlock, new Location($object->getLine()), $returnType);
47+
$function = new FunctionDescriptor(
48+
$object->fqsen,
49+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
50+
new Location($object->getLine()),
51+
(new Type())->fromPhpParser($object->getReturnType())
52+
);
6753

6854
foreach ($object->params as $param) {
6955
$strategy = $strategies->findMatching($param);

src/phpDocumentor/Reflection/Php/Factory/GlobalConstant.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ public function matches($object) : bool
5757
*/
5858
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
5959
{
60-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
61-
$default = null;
62-
if ($object->getValue() !== null) {
63-
$default = $this->valueConverter->prettyPrintExpr($object->getValue());
64-
}
65-
66-
return new ConstantElement($object->getFqsen(), $docBlock, $default, new Location($object->getLine()));
60+
return new ConstantElement(
61+
$object->getFqsen(),
62+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
63+
$object->getValue() !== null ? $this->valueConverter->prettyPrintExpr($object->getValue()) : null,
64+
new Location($object->getLine())
65+
);
6766
}
6867
}

src/phpDocumentor/Reflection/Php/Factory/Method.php

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@
1818
use phpDocumentor\Reflection\Php\ProjectFactoryStrategy;
1919
use phpDocumentor\Reflection\Php\StrategyContainer;
2020
use phpDocumentor\Reflection\Php\Visibility;
21-
use phpDocumentor\Reflection\TypeResolver;
2221
use phpDocumentor\Reflection\Types\Context;
23-
use PhpParser\Node\NullableType;
2422
use PhpParser\Node\Stmt\ClassMethod;
25-
use PhpParser\Node\UnionType;
2623

2724
/**
2825
* Strategy to create MethodDescriptor and arguments when applicable.
@@ -45,31 +42,15 @@ public function matches($object) : bool
4542
*/
4643
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
4744
{
48-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
49-
50-
$returnType = null;
51-
if ($object->getReturnType() !== null) {
52-
$typeResolver = new TypeResolver();
53-
if ($object->getReturnType() instanceof NullableType) {
54-
$typeString = '?' . $object->getReturnType()->type;
55-
} elseif ($object->getReturnType() instanceof UnionType) {
56-
$typeString = $object->getReturnType()->getType();
57-
} else {
58-
$typeString = $object->getReturnType()->toString();
59-
}
60-
61-
$returnType = $typeResolver->resolve($typeString, $context);
62-
}
63-
6445
$method = new MethodDescriptor(
6546
$object->fqsen,
6647
$this->buildVisibility($object),
67-
$docBlock,
48+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
6849
$object->isAbstract(),
6950
$object->isStatic(),
7051
$object->isFinal(),
7152
new Location($object->getLine()),
72-
$returnType
53+
(new Type())->fromPhpParser($object->getReturnType())
7354
);
7455

7556
foreach ($object->params as $param) {

src/phpDocumentor/Reflection/Php/Factory/Property.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,19 @@ public function matches($object) : bool
5858
*/
5959
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
6060
{
61-
$visibility = $this->buildVisibility($object);
6261
$default = null;
6362
if ($object->getDefault() !== null) {
6463
$default = $this->valueConverter->prettyPrintExpr($object->getDefault());
6564
}
6665

67-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
68-
6966
return new PropertyDescriptor(
7067
$object->getFqsen(),
71-
$visibility,
72-
$docBlock,
68+
$this->buildVisibility($object),
69+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
7370
$default,
7471
$object->isStatic(),
75-
new Location($object->getLine())
72+
new Location($object->getLine()),
73+
(new Type())->fromPhpParser($object->getType())
7674
);
7775
}
7876

src/phpDocumentor/Reflection/Php/Factory/PropertyIterator.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
use phpDocumentor\Reflection\Fqsen;
1818
use PhpParser\Comment\Doc;
1919
use PhpParser\Node\Expr;
20+
use PhpParser\Node\Identifier;
21+
use PhpParser\Node\Name;
22+
use PhpParser\Node\NullableType;
2023
use PhpParser\Node\Stmt\Property as PropertyNode;
24+
use PhpParser\Node\UnionType;
2125

2226
/**
2327
* This class acts like a combination of a PropertyNode and PropertyProperty to
@@ -79,6 +83,16 @@ public function getLine() : int
7983
return $this->property->getLine();
8084
}
8185

86+
/**
87+
* Gets the type of the property.
88+
*
89+
* @return Identifier|Name|NullableType|UnionType|null
90+
*/
91+
public function getType()
92+
{
93+
return $this->property->type;
94+
}
95+
8296
/**
8397
* Gets the doc comment of the node.
8498
*

src/phpDocumentor/Reflection/Php/Factory/Trait_.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ public function matches($object) : bool
4545
*/
4646
protected function doCreate($object, StrategyContainer $strategies, ?Context $context = null)
4747
{
48-
$docBlock = $this->createDocBlock($strategies, $object->getDocComment(), $context);
49-
50-
$trait = new TraitElement($object->fqsen, $docBlock, new Location($object->getLine()));
48+
$trait = new TraitElement(
49+
$object->fqsen,
50+
$this->createDocBlock($strategies, $object->getDocComment(), $context),
51+
new Location($object->getLine())
52+
);
5153

5254
if (isset($object->stmts)) {
5355
foreach ($object->stmts as $stmt) {
5456
switch (get_class($stmt)) {
5557
case PropertyNode::class:
5658
$properties = new PropertyIterator($stmt);
5759
foreach ($properties as $property) {
58-
$element = $this->createMember($property, $strategies, $context);
59-
$trait->addProperty($element);
60+
$trait->addProperty($this->createMember($property, $strategies, $context));
6061
}
6162
break;
6263
case ClassMethod::class:
63-
$method = $this->createMember($stmt, $strategies, $context);
64-
$trait->addMethod($method);
64+
$trait->addMethod($this->createMember($stmt, $strategies, $context));
6565
break;
6666
case TraitUse::class:
6767
foreach ($stmt->traits as $use) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link http://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Reflection\Php\Factory;
15+
16+
use phpDocumentor\Reflection\Type as TypeElement;
17+
use phpDocumentor\Reflection\TypeResolver;
18+
use phpDocumentor\Reflection\Types\Context;
19+
use PhpParser\Node\Identifier;
20+
use PhpParser\Node\Name;
21+
use PhpParser\Node\NullableType;
22+
use PhpParser\Node\UnionType;
23+
use function implode;
24+
25+
final class Type
26+
{
27+
/**
28+
* @param Identifier|Name|NullableType|UnionType|null $type
29+
*/
30+
public function fromPhpParser($type, ?Context $context = null) : ?TypeElement
31+
{
32+
if ($type === null) {
33+
return null;
34+
}
35+
36+
$typeResolver = new TypeResolver();
37+
if ($type instanceof NullableType) {
38+
return $typeResolver->resolve('?' . $type->type, $context);
39+
}
40+
41+
if ($type instanceof UnionType) {
42+
return $typeResolver->resolve(implode('|', $type->types), $context);
43+
}
44+
45+
return $typeResolver->resolve($type->toString(), $context);
46+
}
47+
}

src/phpDocumentor/Reflection/Php/Property.php

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use phpDocumentor\Reflection\Element;
1818
use phpDocumentor\Reflection\Fqsen;
1919
use phpDocumentor\Reflection\Location;
20+
use phpDocumentor\Reflection\Type;
2021

2122
/**
2223
* Descriptor representing a property.
@@ -44,6 +45,9 @@ final class Property implements Element
4445
/** @var Location */
4546
private $location;
4647

48+
/** @var Type|null */
49+
private $type;
50+
4751
/**
4852
* @param Visibility|null $visibility when null is provided a default 'public' is set.
4953
*/
@@ -53,24 +57,16 @@ public function __construct(
5357
?DocBlock $docBlock = null,
5458
?string $default = null,
5559
bool $static = false,
56-
?Location $location = null
60+
?Location $location = null,
61+
?Type $type = null
5762
) {
58-
if ($location === null) {
59-
$location = new Location(-1);
60-
}
61-
62-
$this->fqsen = $fqsen;
63-
$this->visibility = $visibility;
64-
$this->docBlock = $docBlock;
65-
$this->default = $default;
66-
$this->static = $static;
67-
$this->location = $location;
68-
69-
if ($this->visibility !== null) {
70-
return;
71-
}
72-
73-
$this->visibility = new Visibility('public');
63+
$this->fqsen = $fqsen;
64+
$this->visibility = $visibility ?: new Visibility('public');
65+
$this->docBlock = $docBlock;
66+
$this->default = $default;
67+
$this->static = $static;
68+
$this->location = $location ?: new Location(-1);
69+
$this->type = $type;
7470
}
7571

7672
/**
@@ -143,4 +139,9 @@ public function getLocation() : Location
143139
{
144140
return $this->location;
145141
}
142+
143+
public function getType() : ?Type
144+
{
145+
return $this->type;
146+
}
146147
}

0 commit comments

Comments
 (0)