Skip to content

Commit e4ac07b

Browse files
committed
Add method support
1 parent cfe9845 commit e4ac07b

File tree

6 files changed

+327
-6
lines changed

6 files changed

+327
-6
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
6+
7+
use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
8+
use phpDocumentor\Reflection\DocBlock\Tag;
9+
use phpDocumentor\Reflection\DocBlock\Tags\Method;
10+
use phpDocumentor\Reflection\DocBlock\Tags\MethodParameter;
11+
use phpDocumentor\Reflection\Type;
12+
use phpDocumentor\Reflection\Types\Context;
13+
use phpDocumentor\Reflection\Types\Void_;
14+
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
15+
use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
16+
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
17+
use Webmozart\Assert\Assert;
18+
19+
use function array_map;
20+
use function trim;
21+
22+
/**
23+
* @internal This class is not part of the BC promise of this library.
24+
*/
25+
final class MethodFactory implements PHPStanFactory
26+
{
27+
private TypeFactory $typeFactory;
28+
private DescriptionFactory $descriptionFactory;
29+
30+
public function __construct(TypeFactory $typeFactory, DescriptionFactory $descriptionFactory)
31+
{
32+
$this->typeFactory = $typeFactory;
33+
$this->descriptionFactory = $descriptionFactory;
34+
}
35+
36+
public function create(PhpDocTagNode $node, ?Context $context): Tag
37+
{
38+
$tagValue = $node->value;
39+
Assert::isInstanceOf($tagValue, MethodTagValueNode::class);
40+
41+
return new Method(
42+
$tagValue->methodName,
43+
[],
44+
$this->createReturnType($tagValue, $context),
45+
$tagValue->isStatic,
46+
$this->descriptionFactory->create($tagValue->description, $context),
47+
false,
48+
array_map(
49+
function (MethodTagValueParameterNode $param) use ($context) {
50+
return new MethodParameter(
51+
trim($param->parameterName, '$'),
52+
$this->typeFactory->createType($param->type, $context),
53+
$param->isReference,
54+
$param->isVariadic,
55+
(string) $param->defaultValue
56+
);
57+
},
58+
$tagValue->parameters
59+
),
60+
);
61+
}
62+
63+
public function supports(PhpDocTagNode $node, ?Context $context): bool
64+
{
65+
return $node->value instanceof MethodTagValueNode;
66+
}
67+
68+
private function createReturnType(MethodTagValueNode $tagValue, ?Context $context): Type
69+
{
70+
return $this->typeFactory->createType($tagValue->returnType, $context) ?? new Void_();
71+
}
72+
}

src/DocBlock/Tags/Factory/TypeFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@ public function __construct(TypeResolver $resolver)
5454
$this->resolver = $resolver;
5555
}
5656

57-
public function createType(TypeNode $type, ?Context $context): ?Type
57+
public function createType(?TypeNode $type, ?Context $context): ?Type
5858
{
59+
if ($type === null) {
60+
return null;
61+
}
62+
5963
switch (get_class($type)) {
6064
case ArrayTypeNode::class:
6165
return new Array_(

src/DocBlock/Tags/Method.php

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Webmozart\Assert\Assert;
2525

2626
use function array_keys;
27+
use function array_map;
2728
use function explode;
2829
use function implode;
2930
use function is_string;
@@ -63,6 +64,9 @@ final class Method extends BaseTag implements Factory\StaticMethod
6364
/** @var bool */
6465
private $returnsReference;
6566

67+
/** @var MethodParameter[] */
68+
private array $parameters;
69+
6670
/**
6771
* @param array<int, array<string, Type|string>> $arguments
6872
* @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
@@ -73,20 +77,24 @@ public function __construct(
7377
?Type $returnType = null,
7478
bool $static = false,
7579
?Description $description = null,
76-
bool $returnsReference = false
80+
bool $returnsReference = false,
81+
?array $parameters = null
7782
) {
7883
Assert::stringNotEmpty($methodName);
7984

8085
if ($returnType === null) {
8186
$returnType = new Void_();
8287
}
8388

89+
$arguments = $this->filterArguments($arguments);
90+
8491
$this->methodName = $methodName;
85-
$this->arguments = $this->filterArguments($arguments);
92+
$this->arguments = $arguments;
8693
$this->returnType = $returnType;
8794
$this->isStatic = $static;
8895
$this->description = $description;
8996
$this->returnsReference = $returnsReference;
97+
$this->parameters = $parameters ?? $this->fromLegacyArguments($arguments);
9098
}
9199

92100
public static function create(
@@ -190,7 +198,14 @@ public static function create(
190198
}
191199
}
192200

193-
return new static($methodName, $arguments, $returnType, $static, $description, $returnsReference);
201+
return new static(
202+
$methodName,
203+
$arguments,
204+
$returnType,
205+
$static,
206+
$description,
207+
$returnsReference
208+
);
194209
}
195210

196211
/**
@@ -210,6 +225,12 @@ public function getArguments(): array
210225
return $this->arguments;
211226
}
212227

228+
/** @return MethodParameter[] */
229+
public function getParameters(): array
230+
{
231+
return $this->parameters;
232+
}
233+
213234
/**
214235
* Checks whether the method tag describes a static method or not.
215236
*
@@ -233,8 +254,11 @@ public function returnsReference(): bool
233254
public function __toString(): string
234255
{
235256
$arguments = [];
236-
foreach ($this->arguments as $argument) {
237-
$arguments[] = $argument['type'] . ' $' . $argument['name'];
257+
foreach ($this->parameters as $parameter) {
258+
$arguments[] = ($parameter->getType() ?? new Mixed_()) . ' ' .
259+
($parameter->isReference() ? '&' : '') .
260+
($parameter->isVariadic() ? '...' : '') .
261+
'$' . $parameter->getName();
238262
}
239263

240264
$argumentStr = '(' . implode(', ', $arguments) . ')';
@@ -301,4 +325,26 @@ private static function stripRestArg(string $argument): string
301325

302326
return $argument;
303327
}
328+
329+
/**
330+
* @param array{name: string, type: Type} $arguments
331+
* @return MethodParameter[]
332+
*/
333+
private function fromLegacyArguments(array $arguments): array
334+
{
335+
trigger_error(
336+
'Create method parameters via legacy format is deprecated add parameters via the constructor',
337+
E_USER_DEPRECATED
338+
);
339+
340+
return array_map(
341+
static function ($arg) {
342+
return new MethodParameter(
343+
$arg['name'],
344+
$arg['type']
345+
);
346+
},
347+
$arguments
348+
);
349+
}
304350
}

src/DocBlock/Tags/MethodParameter.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
/**
3+
* This file is part of phpDocumentor.
4+
*
5+
* For the full copyright and license information, please view the LICENSE
6+
* file that was distributed with this source code.
7+
*
8+
* @link http://phpdoc.org
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace phpDocumentor\Reflection\DocBlock\Tags;
14+
15+
use phpDocumentor\Reflection\Type;
16+
17+
final class MethodParameter
18+
{
19+
/** @var Type */
20+
private $type;
21+
22+
/** @var bool */
23+
private $isReference;
24+
25+
/** @var bool */
26+
private $isVariadic;
27+
28+
/** @var string */
29+
private $name;
30+
31+
/** @var string|null */
32+
private $defaultValue;
33+
34+
public function __construct(
35+
string $name,
36+
Type $type,
37+
bool $isReference = false,
38+
bool $isVariadic = false,
39+
?string $defaultValue = null
40+
) {
41+
$this->type = $type;
42+
$this->isReference = $isReference;
43+
$this->isVariadic = $isVariadic;
44+
$this->name = $name;
45+
$this->defaultValue = $defaultValue;
46+
}
47+
48+
public function getName(): string
49+
{
50+
return $this->name;
51+
}
52+
53+
public function getType(): Type
54+
{
55+
return $this->type;
56+
}
57+
58+
public function isReference(): bool
59+
{
60+
return $this->isReference;
61+
}
62+
63+
public function isVariadic(): bool
64+
{
65+
return $this->isVariadic;
66+
}
67+
68+
public function getDefaultValue(): ?string
69+
{
70+
return $this->defaultValue;
71+
}
72+
}

src/DocBlockFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public static function createInstance(array $additionalTags = []): self
8989
$tagFactory->registerTagHandler('property', $phpstanTagFactory);
9090
$tagFactory->registerTagHandler('property-read', $phpstanTagFactory);
9191
$tagFactory->registerTagHandler('property-write', $phpstanTagFactory);
92+
$tagFactory->registerTagHandler('method', $phpstanTagFactory);
9293

9394
$docBlockFactory = new self($descriptionFactory, $tagFactory);
9495
foreach ($additionalTags as $tagName => $tagHandler) {

0 commit comments

Comments
 (0)