Skip to content

Commit e675935

Browse files
author
smoench
committed
add interface-string
1 parent b6a886b commit e675935

File tree

5 files changed

+176
-1
lines changed

5 files changed

+176
-1
lines changed

src/TypeResolver.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use phpDocumentor\Reflection\Types\Context;
2323
use phpDocumentor\Reflection\Types\Expression;
2424
use phpDocumentor\Reflection\Types\Integer;
25+
use phpDocumentor\Reflection\Types\InterfaceString;
2526
use phpDocumentor\Reflection\Types\Intersection;
2627
use phpDocumentor\Reflection\Types\Iterable_;
2728
use phpDocumentor\Reflection\Types\Nullable;
@@ -71,6 +72,7 @@ final class TypeResolver
7172
private $keywords = [
7273
'string' => Types\String_::class,
7374
'class-string' => Types\ClassString::class,
75+
'interface-string' => Types\InterfaceString::class,
7476
'html-escaped-string' => PseudoTypes\HtmlEscapedString::class,
7577
'lowercase-string' => PseudoTypes\LowercaseString::class,
7678
'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class,
@@ -246,6 +248,8 @@ private function parseTypes(ArrayIterator $tokens, Context $context, int $parser
246248
if ($classType !== null) {
247249
if ((string) $classType === 'class-string') {
248250
$types[] = $this->resolveClassString($tokens, $context);
251+
} elseif ((string) $classType === 'interface-string') {
252+
$types[] = $this->resolveInterfaceString($tokens, $context);
249253
} else {
250254
$types[] = $this->resolveCollection($tokens, $classType, $context);
251255
}
@@ -455,6 +459,39 @@ private function resolveClassString(ArrayIterator $tokens, Context $context) : T
455459
return new ClassString($classType->getFqsen());
456460
}
457461

462+
/**
463+
* Resolves class string
464+
*
465+
* @param ArrayIterator<int, (string|null)> $tokens
466+
*/
467+
private function resolveInterfaceString(ArrayIterator $tokens, Context $context) : Type
468+
{
469+
$tokens->next();
470+
471+
$classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
472+
473+
if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
474+
throw new RuntimeException(
475+
$classType . ' is not a interface string'
476+
);
477+
}
478+
479+
$token = $tokens->current();
480+
if ($token !== '>') {
481+
if (empty($token)) {
482+
throw new RuntimeException(
483+
'interface-string: ">" is missing'
484+
);
485+
}
486+
487+
throw new RuntimeException(
488+
'Unexpected character "' . $token . '", ">" is missing'
489+
);
490+
}
491+
492+
return new InterfaceString($classType->getFqsen());
493+
}
494+
458495
/**
459496
* Resolves the collection values and keys
460497
*

src/Types/InterfaceString.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\Types;
15+
16+
use phpDocumentor\Reflection\Fqsen;
17+
use phpDocumentor\Reflection\Type;
18+
19+
/**
20+
* Value Object representing the type 'string'.
21+
*
22+
* @psalm-immutable
23+
*/
24+
final class InterfaceString implements Type
25+
{
26+
/** @var Fqsen|null */
27+
private $fqsen;
28+
29+
/**
30+
* Initializes this representation of a class string with the given Fqsen.
31+
*/
32+
public function __construct(?Fqsen $fqsen = null)
33+
{
34+
$this->fqsen = $fqsen;
35+
}
36+
37+
/**
38+
* Returns the FQSEN associated with this object.
39+
*/
40+
public function getFqsen() : ?Fqsen
41+
{
42+
return $this->fqsen;
43+
}
44+
45+
/**
46+
* Returns a rendered output of the Type as it would be used in a DocBlock.
47+
*/
48+
public function __toString() : string
49+
{
50+
if ($this->fqsen === null) {
51+
return 'interface-string';
52+
}
53+
54+
return 'interface-string<' . (string) $this->fqsen . '>';
55+
}
56+
}

tests/unit/TypeResolverTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use phpDocumentor\Reflection\Types\Context;
2121
use phpDocumentor\Reflection\Types\Expression;
2222
use phpDocumentor\Reflection\Types\Integer;
23+
use phpDocumentor\Reflection\Types\InterfaceString;
2324
use phpDocumentor\Reflection\Types\Intersection;
2425
use phpDocumentor\Reflection\Types\Iterable_;
2526
use phpDocumentor\Reflection\Types\Null_;
@@ -79,6 +80,30 @@ public function testResolvingClassStrings(string $classString, bool $throwsExcep
7980
$this->assertInstanceOf(ClassString::class, $resolvedType);
8081
}
8182

83+
/**
84+
* @uses \phpDocumentor\Reflection\Types\Context
85+
* @uses \phpDocumentor\Reflection\Types\Object_
86+
* @uses \phpDocumentor\Reflection\Types\String_
87+
*
88+
* @covers ::__construct
89+
* @covers ::resolve
90+
* @covers ::<private>
91+
*
92+
* @dataProvider provideInterfaceStrings
93+
*/
94+
public function testResolvingInterfaceStrings(string $interfaceString, bool $throwsException) : void
95+
{
96+
$fixture = new TypeResolver();
97+
98+
if ($throwsException) {
99+
$this->expectException('RuntimeException');
100+
}
101+
102+
$resolvedType = $fixture->resolve($interfaceString, new Context(''));
103+
104+
$this->assertInstanceOf(InterfaceString::class, $resolvedType);
105+
}
106+
82107
/**
83108
* @uses \phpDocumentor\Reflection\Types\Context
84109
* @uses \phpDocumentor\Reflection\Types\Object_
@@ -748,6 +773,20 @@ public function provideClassStrings() : array
748773
];
749774
}
750775

776+
/**
777+
* Returns a list of interface string types and whether they throw an exception.
778+
*
779+
* @return (string|bool)[][]
780+
*/
781+
public function provideInterfaceStrings() : array
782+
{
783+
return [
784+
['interface-string<\phpDocumentor\Reflection>', false],
785+
['interface-string<\phpDocumentor\Reflection\DocBlock>', false],
786+
['interface-string<string>', true],
787+
];
788+
}
789+
751790
/**
752791
* Provides a list of FQSENs to test the resolution patterns with.
753792
*

tests/unit/Types/ClassStringTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function testClassStringStringifyCorrectly(ClassString $array, string $ex
3636
public function provideClassStrings() : array
3737
{
3838
return [
39-
'generic clss string' => [new ClassString(), 'class-string'],
39+
'generic class string' => [new ClassString(), 'class-string'],
4040
'typed class string' => [new ClassString(new Fqsen('\Foo\Bar')), 'class-string<\Foo\Bar>'],
4141
];
4242
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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\Types;
15+
16+
use phpDocumentor\Reflection\Fqsen;
17+
use PHPUnit\Framework\TestCase;
18+
19+
/**
20+
* @coversDefaultClass \phpDocumentor\Reflection\Types\InterfaceString
21+
*/
22+
class InterfaceStringTest extends TestCase
23+
{
24+
/**
25+
* @dataProvider provideInterfaceStrings
26+
* @covers ::__toString
27+
*/
28+
public function testInterfaceStringStringifyCorrectly(InterfaceString $array, string $expectedString) : void
29+
{
30+
$this->assertSame($expectedString, (string) $array);
31+
}
32+
33+
/**
34+
* @return mixed[]
35+
*/
36+
public function provideInterfaceStrings() : array
37+
{
38+
return [
39+
'generic interface string' => [new InterfaceString(), 'interface-string'],
40+
'typed interface string' => [new InterfaceString(new Fqsen('\Foo\Bar')), 'interface-string<\Foo\Bar>'],
41+
];
42+
}
43+
}

0 commit comments

Comments
 (0)