Skip to content

Commit 443d86e

Browse files
committed
Param: fix phpdoc with reference hint
fix issue #251
1 parent f3ab307 commit 443d86e

File tree

2 files changed

+123
-9
lines changed

2 files changed

+123
-9
lines changed

src/DocBlock/Tags/Param.php

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,22 @@ final class Param extends TagWithType implements Factory\StaticMethod
3838
/** @var bool determines whether this is a variadic argument */
3939
private $isVariadic;
4040

41+
/** @var bool determines whether this is passed by reference */
42+
private $isReference;
43+
4144
public function __construct(
4245
?string $variableName,
4346
?Type $type = null,
4447
bool $isVariadic = false,
45-
?Description $description = null
48+
?Description $description = null,
49+
bool $isReference = false
4650
) {
4751
$this->name = 'param';
4852
$this->variableName = $variableName;
4953
$this->type = $type;
5054
$this->isVariadic = $isVariadic;
5155
$this->description = $description;
56+
$this->isReference = $isReference;
5257
}
5358

5459
public static function create(
@@ -67,6 +72,7 @@ public static function create(
6772
$parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
6873
$variableName = '';
6974
$isVariadic = false;
75+
$isReference = false;
7076

7177
// if the first item that is encountered is not a variable; it is a type
7278
if ($firstPart && $firstPart[0] !== '$') {
@@ -76,26 +82,43 @@ public static function create(
7682
array_unshift($parts, $firstPart);
7783
}
7884

79-
// if the next item starts with a $ or ...$ it must be the variable name
80-
if (isset($parts[0]) && (strpos($parts[0], '$') === 0 || strpos($parts[0], '...$') === 0)) {
85+
// if the next item starts with a $ or ...$ or &$ or &...$ it must be the variable name
86+
if (
87+
isset($parts[0])
88+
&&
89+
(
90+
strpos($parts[0], '$') === 0
91+
||
92+
strpos($parts[0], '...$') === 0
93+
||
94+
strpos($parts[0], '&$') === 0
95+
||
96+
strpos($parts[0], '&...$') === 0
97+
)
98+
) {
8199
$variableName = array_shift($parts);
82100
array_shift($parts);
83101

84102
Assert::notNull($variableName);
85103

86-
if (strpos($variableName, '...') === 0) {
87-
$isVariadic = true;
88-
$variableName = substr($variableName, 3);
89-
}
90-
91104
if (strpos($variableName, '$') === 0) {
92105
$variableName = substr($variableName, 1);
106+
} elseif(strpos($variableName, '&$') === 0) {
107+
$isReference = true;
108+
$variableName = substr($variableName, 2);
109+
} elseif (strpos($variableName, '...$') === 0) {
110+
$isVariadic = true;
111+
$variableName = substr($variableName, 4);
112+
} elseif (strpos($variableName, '&...$') === 0) {
113+
$isVariadic = true;
114+
$isReference = true;
115+
$variableName = substr($variableName, 5);
93116
}
94117
}
95118

96119
$description = $descriptionFactory->create(implode('', $parts), $context);
97120

98-
return new static($variableName, $type, $isVariadic, $description);
121+
return new static($variableName, $type, $isVariadic, $description, $isReference);
99122
}
100123

101124
/**
@@ -114,12 +137,21 @@ public function isVariadic() : bool
114137
return $this->isVariadic;
115138
}
116139

140+
/**
141+
* Returns whether this tag is passed by reference.
142+
*/
143+
public function isReference() : bool
144+
{
145+
return $this->isReference;
146+
}
147+
117148
/**
118149
* Returns a string representation for this tag.
119150
*/
120151
public function __toString() : string
121152
{
122153
return ($this->type ? $this->type . ' ' : '')
154+
. ($this->isReference() ? '&' : '')
123155
. ($this->isVariadic() ? '...' : '')
124156
. ($this->variableName !== null ? '$' . $this->variableName : '')
125157
. ($this->description ? ' ' . $this->description : '');

tests/unit/DocBlock/Tags/ParamTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,94 @@ public function testFactoryMethod() : void
174174
$description = new Description('My Description');
175175
$descriptionFactory->shouldReceive('create')->with('My Description', $context)->andReturn($description);
176176

177+
$fixture = Param::create('string $myParameter My Description', $typeResolver, $descriptionFactory, $context);
178+
179+
$this->assertSame('string $myParameter My Description', (string) $fixture);
180+
$this->assertSame('myParameter', $fixture->getVariableName());
181+
$this->assertInstanceOf(String_::class, $fixture->getType());
182+
$this->assertFalse($fixture->isVariadic());
183+
$this->assertFalse($fixture->isReference());
184+
$this->assertSame($description, $fixture->getDescription());
185+
}
186+
187+
/**
188+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Param::<public>
189+
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
190+
* @uses \phpDocumentor\Reflection\DocBlock\Description
191+
* @uses \phpDocumentor\Reflection\Types\Context
192+
*
193+
* @covers ::create
194+
*/
195+
public function testFactoryMethodWithVariadic() : void
196+
{
197+
$typeResolver = new TypeResolver();
198+
$descriptionFactory = m::mock(DescriptionFactory::class);
199+
$context = new Context('');
200+
201+
$description = new Description('My Description');
202+
$descriptionFactory->shouldReceive('create')->with('My Description', $context)->andReturn($description);
203+
177204
$fixture = Param::create('string ...$myParameter My Description', $typeResolver, $descriptionFactory, $context);
178205

179206
$this->assertSame('string ...$myParameter My Description', (string) $fixture);
180207
$this->assertSame('myParameter', $fixture->getVariableName());
181208
$this->assertInstanceOf(String_::class, $fixture->getType());
182209
$this->assertTrue($fixture->isVariadic());
210+
$this->assertFalse($fixture->isReference());
211+
$this->assertSame($description, $fixture->getDescription());
212+
}
213+
214+
/**
215+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Param::<public>
216+
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
217+
* @uses \phpDocumentor\Reflection\DocBlock\Description
218+
* @uses \phpDocumentor\Reflection\Types\Context
219+
*
220+
* @covers ::create
221+
*/
222+
public function testFactoryMethodWithReference() : void
223+
{
224+
$typeResolver = new TypeResolver();
225+
$descriptionFactory = m::mock(DescriptionFactory::class);
226+
$context = new Context('');
227+
228+
$description = new Description('My Description');
229+
$descriptionFactory->shouldReceive('create')->with('My Description', $context)->andReturn($description);
230+
231+
$fixture = Param::create('string &$myParameter My Description', $typeResolver, $descriptionFactory, $context);
232+
233+
$this->assertSame('string &$myParameter My Description', (string) $fixture);
234+
$this->assertSame('myParameter', $fixture->getVariableName());
235+
$this->assertInstanceOf(String_::class, $fixture->getType());
236+
$this->assertFalse($fixture->isVariadic());
237+
$this->assertTrue($fixture->isReference());
238+
$this->assertSame($description, $fixture->getDescription());
239+
}
240+
241+
/**
242+
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Param::<public>
243+
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
244+
* @uses \phpDocumentor\Reflection\DocBlock\Description
245+
* @uses \phpDocumentor\Reflection\Types\Context
246+
*
247+
* @covers ::create
248+
*/
249+
public function testFactoryMethodWithVariadicReference() : void
250+
{
251+
$typeResolver = new TypeResolver();
252+
$descriptionFactory = m::mock(DescriptionFactory::class);
253+
$context = new Context('');
254+
255+
$description = new Description('My Description');
256+
$descriptionFactory->shouldReceive('create')->with('My Description', $context)->andReturn($description);
257+
258+
$fixture = Param::create('string &...$myParameter My Description', $typeResolver, $descriptionFactory, $context);
259+
260+
$this->assertSame('string &...$myParameter My Description', (string) $fixture);
261+
$this->assertSame('myParameter', $fixture->getVariableName());
262+
$this->assertInstanceOf(String_::class, $fixture->getType());
263+
$this->assertTrue($fixture->isVariadic());
264+
$this->assertTrue($fixture->isReference());
183265
$this->assertSame($description, $fixture->getDescription());
184266
}
185267

0 commit comments

Comments
 (0)