├── src
├── PseudoTypes
│ ├── ObjectShapeItem.php
│ ├── ListShapeItem.php
│ ├── ListShape.php
│ ├── ArrayShapeItem.php
│ ├── PublicPropertiesOf.php
│ ├── PrivatePropertiesOf.php
│ ├── ProtectedPropertiesOf.php
│ ├── NoReturn.php
│ ├── NeverReturn.php
│ ├── False_.php
│ ├── NeverReturns.php
│ ├── True_.php
│ ├── TruthyString.php
│ ├── NonFalsyString.php
│ ├── OpenResource.php
│ ├── ClosedResource.php
│ ├── NonPositiveInteger.php
│ ├── ObjectShape.php
│ ├── LiteralString.php
│ ├── NegativeInteger.php
│ ├── NonZeroInteger.php
│ ├── NumericString.php
│ ├── PositiveInteger.php
│ ├── CallableString.php
│ ├── LowercaseString.php
│ ├── NonEmptyString.php
│ ├── NonNegativeInteger.php
│ ├── HtmlEscapedString.php
│ ├── NonEmptyLowercaseString.php
│ ├── FloatValue.php
│ ├── IntegerValue.php
│ ├── KeyOf.php
│ ├── StringValue.php
│ ├── CallableArray.php
│ ├── ValueOf.php
│ ├── IntMaskOf.php
│ ├── ArrayKey.php
│ ├── Scalar.php
│ ├── IntMask.php
│ ├── List_.php
│ ├── NonEmptyArray.php
│ ├── Generic.php
│ ├── NonEmptyList.php
│ ├── PropertiesOf.php
│ ├── ArrayShape.php
│ ├── ShapeItem.php
│ ├── ConstExpression.php
│ ├── Numeric_.php
│ ├── EnumString.php
│ ├── ClassString.php
│ ├── TraitString.php
│ ├── InterfaceString.php
│ ├── IntegerRange.php
│ ├── OffsetAccess.php
│ ├── Conditional.php
│ └── ConditionalForParameter.php
├── PseudoType.php
├── Type.php
├── Types
│ ├── Float_.php
│ ├── Integer.php
│ ├── Boolean.php
│ ├── Null_.php
│ ├── String_.php
│ ├── Mixed_.php
│ ├── Resource_.php
│ ├── Array_.php
│ ├── Parent_.php
│ ├── Never_.php
│ ├── Void_.php
│ ├── Iterable_.php
│ ├── This.php
│ ├── Compound.php
│ ├── Intersection.php
│ ├── Expression.php
│ ├── Nullable.php
│ ├── Self_.php
│ ├── Static_.php
│ ├── Object_.php
│ ├── Callable_.php
│ ├── CallableParameter.php
│ ├── AbstractList.php
│ ├── Context.php
│ ├── AggregatedType.php
│ └── ContextFactory.php
├── FqsenResolver.php
└── TypeResolver.php
├── .phpdoc
└── template
│ └── base.html.twig
├── docs
├── index.rst
├── generics.rst
├── getting-started.rst
└── upgrade-v1-to-v2.rst
├── LICENSE
├── composer.json
├── phpdoc.dist.xml
└── README.md
/src/PseudoTypes/ObjectShapeItem.php:
--------------------------------------------------------------------------------
1 | getItems()) . '}';
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ArrayShapeItem.php:
--------------------------------------------------------------------------------
1 | type . '>';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/PseudoTypes/PrivatePropertiesOf.php:
--------------------------------------------------------------------------------
1 | type . '>';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ProtectedPropertiesOf.php:
--------------------------------------------------------------------------------
1 | type . '>';
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Types/Float_.php:
--------------------------------------------------------------------------------
1 | valueType === null) {
29 | return 'iterable';
30 | }
31 |
32 | if ($this->keyType) {
33 | return 'iterable<' . $this->keyType . ', ' . $this->valueType . '>';
34 | }
35 |
36 | return 'iterable<' . $this->valueType . '>';
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Types/This.php:
--------------------------------------------------------------------------------
1 | items = $items;
22 | }
23 |
24 | /**
25 | * @return ObjectShapeItem[]
26 | */
27 | public function getItems(): array
28 | {
29 | return $this->items;
30 | }
31 |
32 | public function underlyingType(): Type
33 | {
34 | return new Object_();
35 | }
36 |
37 | public function __toString(): string
38 | {
39 | return 'object{' . implode(', ', $this->items) . '}';
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/generics.rst:
--------------------------------------------------------------------------------
1 | ========
2 | Generics
3 | ========
4 |
5 | This project is capable of parsing generics notation as used by PHPStan. But it has some limitations, in regards to
6 | PHPStan. The main difference is that PHPStan does scan your whole codebase to find out what types are used in generics,
7 | while this library only parses the types as they are given to it.
8 |
9 | This means that if you use a generic type like.
10 |
11 | .. code:: php
12 |
13 | namespace MyApp;
14 |
15 | /**
16 | * @template T of Item
17 | */
18 | class Collection {
19 |
20 | /**
21 | * @return T[]
22 | */
23 | public function getItems() : array {
24 | // ...
25 | }
26 | }
27 |
28 | The type resolver will not be able to determine what ``T`` is. In fact there is no difference between ``T`` and any other relative
29 | used classname like ``Item``. The resolver will handle ``T`` as a normal class name. In this example it will resolve ``T`` to ``\MyApp\T``.
30 |
--------------------------------------------------------------------------------
/src/PseudoTypes/LiteralString.php:
--------------------------------------------------------------------------------
1 | value = $value;
29 | }
30 |
31 | public function getValue(): float
32 | {
33 | return $this->value;
34 | }
35 |
36 | public function underlyingType(): Type
37 | {
38 | return new Float_();
39 | }
40 |
41 | public function __toString(): string
42 | {
43 | return (string) $this->value;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/PseudoTypes/IntegerValue.php:
--------------------------------------------------------------------------------
1 | value = $value;
29 | }
30 |
31 | public function getValue(): int
32 | {
33 | return $this->value;
34 | }
35 |
36 | public function underlyingType(): Type
37 | {
38 | return new Integer();
39 | }
40 |
41 | public function __toString(): string
42 | {
43 | return (string) $this->value;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/PseudoTypes/KeyOf.php:
--------------------------------------------------------------------------------
1 | type = $type;
32 | }
33 |
34 | public function getType(): Type
35 | {
36 | return $this->type;
37 | }
38 |
39 | public function underlyingType(): Type
40 | {
41 | return new ArrayKey();
42 | }
43 |
44 | public function __toString(): string
45 | {
46 | return 'key-of<' . $this->type . '>';
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2010 Mike van Riel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/PseudoTypes/StringValue.php:
--------------------------------------------------------------------------------
1 | value = $value;
31 | }
32 |
33 | public function getValue(): string
34 | {
35 | return $this->value;
36 | }
37 |
38 | public function underlyingType(): Type
39 | {
40 | return new String_();
41 | }
42 |
43 | public function __toString(): string
44 | {
45 | return sprintf('"%s"', $this->value);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PseudoTypes/CallableArray.php:
--------------------------------------------------------------------------------
1 | type = $type;
33 | }
34 |
35 | public function getType(): Type
36 | {
37 | return $this->type;
38 | }
39 |
40 | public function underlyingType(): Type
41 | {
42 | return new Mixed_();
43 | }
44 |
45 | public function __toString(): string
46 | {
47 | return 'value-of<' . $this->type . '>';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Types/Compound.php:
--------------------------------------------------------------------------------
1 | $types
33 | */
34 | public function __construct(array $types)
35 | {
36 | parent::__construct($types, '|');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/PseudoTypes/IntMaskOf.php:
--------------------------------------------------------------------------------
1 | type = $type;
33 | }
34 |
35 | public function getType(): Type
36 | {
37 | return $this->type;
38 | }
39 |
40 | public function underlyingType(): Type
41 | {
42 | return new Integer();
43 | }
44 |
45 | public function __toString(): string
46 | {
47 | return 'int-mask-of<' . $this->type . '>';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Types/Intersection.php:
--------------------------------------------------------------------------------
1 | $types
32 | */
33 | public function __construct(array $types)
34 | {
35 | parent::__construct($types, '&');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ArrayKey.php:
--------------------------------------------------------------------------------
1 | types = $types;
35 | }
36 |
37 | /**
38 | * @return Type[]
39 | */
40 | public function getTypes(): array
41 | {
42 | return $this->types;
43 | }
44 |
45 | public function underlyingType(): Type
46 | {
47 | return new Integer();
48 | }
49 |
50 | public function __toString(): string
51 | {
52 | return 'int-mask<' . implode(', ', $this->types) . '>';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Types/Expression.php:
--------------------------------------------------------------------------------
1 | valueType = $valueType;
34 | }
35 |
36 | /**
37 | * Returns the value for the keys of this array.
38 | */
39 | public function getValueType(): Type
40 | {
41 | return $this->valueType;
42 | }
43 |
44 | /**
45 | * Returns a rendered output of the Type as it would be used in a DocBlock.
46 | */
47 | public function __toString(): string
48 | {
49 | return '(' . $this->valueType . ')';
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PseudoTypes/List_.php:
--------------------------------------------------------------------------------
1 | valueType === null) {
44 | return 'list';
45 | }
46 |
47 | return 'list<' . $this->valueType . '>';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Types/Nullable.php:
--------------------------------------------------------------------------------
1 | realType = $realType;
34 | }
35 |
36 | /**
37 | * Provide access to the actual type directly, if needed.
38 | */
39 | public function getActualType(): Type
40 | {
41 | return $this->realType;
42 | }
43 |
44 | /**
45 | * Returns a rendered output of the Type as it would be used in a DocBlock.
46 | */
47 | public function __toString(): string
48 | {
49 | return '?' . $this->realType->__toString();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PseudoTypes/NonEmptyArray.php:
--------------------------------------------------------------------------------
1 | valueType, $this->keyType);
30 | }
31 |
32 | /**
33 | * Returns a rendered output of the Type as it would be used in a DocBlock.
34 | */
35 | public function __toString(): string
36 | {
37 | if ($this->valueType === null) {
38 | return 'non-empty-array';
39 | }
40 |
41 | if ($this->keyType) {
42 | return 'non-empty-array<' . $this->keyType . ', ' . $this->valueType . '>';
43 | }
44 |
45 | return 'non-empty-array<' . $this->valueType . '>';
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/PseudoTypes/Generic.php:
--------------------------------------------------------------------------------
1 | types = $types;
40 | }
41 |
42 | /**
43 | * @return Type[]
44 | */
45 | public function getTypes(): array
46 | {
47 | return $this->types;
48 | }
49 |
50 | public function __toString(): string
51 | {
52 | $objectType = (string) ($this->fqsen ?? 'object');
53 |
54 | return $objectType . '<' . implode(', ', $this->types) . '>';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/docs/getting-started.rst:
--------------------------------------------------------------------------------
1 | ===============
2 | Getting started
3 | ===============
4 |
5 | On this page you will find a brief introduction on how to use the TypeResolver in your project.
6 |
7 | Installation
8 | ============
9 |
10 | The TypeResolver is available on Packagist and can be installed using Composer:
11 |
12 | .. code:: bash
13 | composer require phpdocumentor/type-resolver
14 |
15 |
16 | General usage
17 | ===========
18 |
19 | After you installed the TypeResolver you can use it in your project. This can be done by creating a new instance
20 | of the :php:class:`\phpDocumentor\Reflection\TypeResolver` class and calling
21 | :php:method:`\phpDocumentor\Reflection\TypeResolver::resolve()` with the type you want to resolve.
22 |
23 | .. code:: php
24 | $typeResolver = new \phpDocumentor\Reflection\TypeResolver();
25 | $type = $typeResolver->resolve('string');
26 | echo get_class($type); // phpDocumentor\Reflection\Types\String_
27 |
28 | The real power of this resolver is in its capability to expand partial class names into fully qualified class names;
29 | but in order to do that we need an additional :php:class:`\phpDocumentor\Reflection\Types\Context` class that
30 | will inform the resolver in which namespace the given expression occurs and which namespace aliases (or imports) apply.
31 |
32 | Read more about the Context class in the next section.
33 |
--------------------------------------------------------------------------------
/src/PseudoTypes/NonEmptyList.php:
--------------------------------------------------------------------------------
1 | valueType, $this->keyType);
31 | }
32 |
33 | public function __construct(?Type $valueType = null)
34 | {
35 | parent::__construct($valueType, new Integer());
36 | }
37 |
38 | /**
39 | * Returns a rendered output of the Type as it would be used in a DocBlock.
40 | */
41 | public function __toString(): string
42 | {
43 | if ($this->valueType === null) {
44 | return 'non-empty-list';
45 | }
46 |
47 | return 'non-empty-list<' . $this->valueType . '>';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/PseudoTypes/PropertiesOf.php:
--------------------------------------------------------------------------------
1 | type = $type;
37 | }
38 |
39 | public function getType(): Type
40 | {
41 | return $this->type;
42 | }
43 |
44 | public function underlyingType(): Type
45 | {
46 | return new Array_(new Mixed_(), new String_());
47 | }
48 |
49 | public function __toString(): string
50 | {
51 | return 'properties-of<' . $this->type . '>';
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ArrayShape.php:
--------------------------------------------------------------------------------
1 | items = $items;
34 | }
35 |
36 | /**
37 | * @return ArrayShapeItem[]
38 | */
39 | public function getItems(): array
40 | {
41 | return $this->items;
42 | }
43 |
44 | public function underlyingType(): Type
45 | {
46 | return new Array_(new Mixed_(), new ArrayKey());
47 | }
48 |
49 | public function __toString(): string
50 | {
51 | return 'array{' . implode(', ', $this->items) . '}';
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ShapeItem.php:
--------------------------------------------------------------------------------
1 | key = $key;
24 | $this->value = $value ?? new Mixed_();
25 | $this->optional = $optional;
26 | }
27 |
28 | public function getKey(): ?string
29 | {
30 | return $this->key;
31 | }
32 |
33 | public function getValue(): Type
34 | {
35 | return $this->value;
36 | }
37 |
38 | public function isOptional(): bool
39 | {
40 | return $this->optional;
41 | }
42 |
43 | public function __toString(): string
44 | {
45 | if ($this->key !== null && $this->key !== '') {
46 | return sprintf(
47 | '%s%s: %s',
48 | $this->key,
49 | $this->optional ? '?' : '',
50 | (string) $this->value
51 | );
52 | }
53 |
54 | return (string) $this->value;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Types/Self_.php:
--------------------------------------------------------------------------------
1 | genericTypes = $genericTypes;
35 | }
36 |
37 | /**
38 | * @return Type[]
39 | */
40 | public function getGenericTypes(): array
41 | {
42 | return $this->genericTypes;
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->genericTypes) {
51 | return 'self<' . implode(', ', $this->genericTypes) . '>';
52 | }
53 |
54 | return 'self';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ConstExpression.php:
--------------------------------------------------------------------------------
1 | owner = $owner;
33 | $this->expression = $expression;
34 | }
35 |
36 | public function getOwner(): Type
37 | {
38 | return $this->owner;
39 | }
40 |
41 | public function getExpression(): string
42 | {
43 | return $this->expression;
44 | }
45 |
46 | public function underlyingType(): Type
47 | {
48 | return new Mixed_();
49 | }
50 |
51 | public function __toString(): string
52 | {
53 | return sprintf('%s::%s', (string) $this->owner, $this->expression);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/PseudoTypes/Numeric_.php:
--------------------------------------------------------------------------------
1 | genericType = $genericType;
33 | }
34 |
35 | public function underlyingType(): Type
36 | {
37 | return new String_();
38 | }
39 |
40 | public function getGenericType(): ?Type
41 | {
42 | return $this->genericType;
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->genericType === null) {
51 | return 'enum-string';
52 | }
53 |
54 | return 'enum-string<' . (string) $this->genericType . '>';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ClassString.php:
--------------------------------------------------------------------------------
1 | genericType = $genericType;
33 | }
34 |
35 | public function underlyingType(): Type
36 | {
37 | return new String_();
38 | }
39 |
40 | public function getGenericType(): ?Type
41 | {
42 | return $this->genericType;
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->genericType === null) {
51 | return 'class-string';
52 | }
53 |
54 | return 'class-string<' . (string) $this->genericType . '>';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/PseudoTypes/TraitString.php:
--------------------------------------------------------------------------------
1 | genericType = $genericType;
33 | }
34 |
35 | public function underlyingType(): Type
36 | {
37 | return new String_();
38 | }
39 |
40 | public function getGenericType(): ?Type
41 | {
42 | return $this->genericType;
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->genericType === null) {
51 | return 'trait-string';
52 | }
53 |
54 | return 'trait-string<' . (string) $this->genericType . '>';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/PseudoTypes/InterfaceString.php:
--------------------------------------------------------------------------------
1 | genericType = $genericType;
33 | }
34 |
35 | public function underlyingType(): Type
36 | {
37 | return new String_();
38 | }
39 |
40 | public function getGenericType(): ?Type
41 | {
42 | return $this->genericType;
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->genericType === null) {
51 | return 'interface-string';
52 | }
53 |
54 | return 'interface-string<' . (string) $this->genericType . '>';
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "phpdocumentor/type-resolver",
3 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
4 | "type": "library",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Mike van Riel",
9 | "email": "me@mikevanriel.com"
10 | }
11 | ],
12 | "require": {
13 | "php": "^7.4 || ^8.0",
14 | "phpdocumentor/reflection-common": "^2.0",
15 | "phpstan/phpdoc-parser": "^2.0",
16 | "doctrine/deprecations": "^1.0"
17 | },
18 | "require-dev": {
19 | "ext-tokenizer": "*",
20 | "phpunit/phpunit": "^9.5",
21 | "phpstan/phpstan": "^2.1",
22 | "phpstan/phpstan-phpunit": "^2.0",
23 | "phpstan/extension-installer": "^1.4",
24 | "phpbench/phpbench": "^1.2",
25 | "psalm/phar": "^4"
26 | },
27 | "autoload": {
28 | "psr-4": {
29 | "phpDocumentor\\Reflection\\": "src"
30 | }
31 | },
32 | "autoload-dev": {
33 | "psr-4": {
34 | "phpDocumentor\\Reflection\\": ["tests/unit", "tests/benchmark"]
35 | }
36 | },
37 | "extra": {
38 | "branch-alias": {
39 | "dev-1.x": "1.x-dev",
40 | "dev-2.x": "2.x-dev"
41 | }
42 | },
43 | "config": {
44 | "platform": {
45 | "php": "7.4.0"
46 | },
47 | "allow-plugins": {
48 | "phpstan/extension-installer": true
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/PseudoTypes/IntegerRange.php:
--------------------------------------------------------------------------------
1 | minValue = $minValue;
36 | $this->maxValue = $maxValue;
37 | }
38 |
39 | public function underlyingType(): Type
40 | {
41 | return new Integer();
42 | }
43 |
44 | public function getMinValue(): string
45 | {
46 | return $this->minValue;
47 | }
48 |
49 | public function getMaxValue(): string
50 | {
51 | return $this->maxValue;
52 | }
53 |
54 | /**
55 | * Returns a rendered output of the Type as it would be used in a DocBlock.
56 | */
57 | public function __toString(): string
58 | {
59 | return 'int<' . $this->minValue . ', ' . $this->maxValue . '>';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/phpdoc.dist.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 | Type Resolver
9 |
10 |
11 |
12 |
13 | latest
14 |
15 |
16 | src/
17 |
18 |
19 |
20 | tests/**/*
21 | build/**/*
22 | var/**/*
23 | vendor/**/*
24 |
25 |
26 | php
27 |
28 |
29 | template
30 | template-extends
31 | template-implements
32 | extends
33 | implements
34 |
35 | phpDocumentor
36 |
37 |
38 |
39 | docs
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/Types/Static_.php:
--------------------------------------------------------------------------------
1 | genericTypes = $genericTypes;
40 | }
41 |
42 | /**
43 | * @return Type[]
44 | */
45 | public function getGenericTypes(): array
46 | {
47 | return $this->genericTypes;
48 | }
49 |
50 | /**
51 | * Returns a rendered output of the Type as it would be used in a DocBlock.
52 | */
53 | public function __toString(): string
54 | {
55 | if ($this->genericTypes) {
56 | return 'static<' . implode(', ', $this->genericTypes) . '>';
57 | }
58 |
59 | return 'static';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/PseudoTypes/OffsetAccess.php:
--------------------------------------------------------------------------------
1 | type = $type;
37 | $this->offset = $offset;
38 | }
39 |
40 | public function getType(): Type
41 | {
42 | return $this->type;
43 | }
44 |
45 | public function getOffset(): Type
46 | {
47 | return $this->offset;
48 | }
49 |
50 | public function underlyingType(): Type
51 | {
52 | return new Mixed_();
53 | }
54 |
55 | public function __toString(): string
56 | {
57 | if (
58 | $this->type instanceof Callable_
59 | || $this->type instanceof ConstExpression
60 | || $this->type instanceof Nullable
61 | ) {
62 | return '(' . $this->type . ')[' . $this->offset . ']';
63 | }
64 |
65 | return $this->type . '[' . $this->offset . ']';
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Types/Object_.php:
--------------------------------------------------------------------------------
1 | fqsen = $fqsen;
51 | }
52 |
53 | /**
54 | * Returns the FQSEN associated with this object.
55 | */
56 | public function getFqsen(): ?Fqsen
57 | {
58 | return $this->fqsen;
59 | }
60 |
61 | public function __toString(): string
62 | {
63 | if ($this->fqsen) {
64 | return (string) $this->fqsen;
65 | }
66 |
67 | return 'object';
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Types/Callable_.php:
--------------------------------------------------------------------------------
1 | identifier = $identifier;
43 | $this->parameters = $parameters;
44 | $this->returnType = $returnType;
45 | }
46 |
47 | public function getIdentifier(): string
48 | {
49 | return $this->identifier;
50 | }
51 |
52 | /** @return CallableParameter[] */
53 | public function getParameters(): array
54 | {
55 | return $this->parameters;
56 | }
57 |
58 | public function getReturnType(): ?Type
59 | {
60 | return $this->returnType;
61 | }
62 |
63 | /**
64 | * Returns a rendered output of the Type as it would be used in a DocBlock.
65 | */
66 | public function __toString(): string
67 | {
68 | if (!$this->parameters && $this->returnType === null) {
69 | return $this->identifier;
70 | }
71 |
72 | if ($this->returnType instanceof self) {
73 | $returnType = '(' . (string) $this->returnType . ')';
74 | } else {
75 | $returnType = (string) $this->returnType;
76 | }
77 |
78 | return $this->identifier . '(' . implode(', ', $this->parameters) . '): ' . $returnType;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Types/CallableParameter.php:
--------------------------------------------------------------------------------
1 | type = $type;
49 | $this->isReference = $isReference;
50 | $this->isVariadic = $isVariadic;
51 | $this->isOptional = $isOptional;
52 | $this->name = $name;
53 | }
54 |
55 | public function getName(): ?string
56 | {
57 | return $this->name;
58 | }
59 |
60 | public function getType(): Type
61 | {
62 | return $this->type;
63 | }
64 |
65 | public function isReference(): bool
66 | {
67 | return $this->isReference;
68 | }
69 |
70 | public function isVariadic(): bool
71 | {
72 | return $this->isVariadic;
73 | }
74 |
75 | public function isOptional(): bool
76 | {
77 | return $this->isOptional;
78 | }
79 |
80 | public function __toString(): string
81 | {
82 | $reference = $this->isReference ? '&' : '';
83 | $variadic = $this->isVariadic ? '...' : '';
84 | $optional = $this->isOptional ? '=' : '';
85 | $name = $this->name !== null ? '$' . $this->name : '';
86 |
87 | return trim($this->type . ' ' . $reference . $variadic . $name . $optional);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/PseudoTypes/Conditional.php:
--------------------------------------------------------------------------------
1 | negated = $negated;
43 | $this->subjectType = $subjectType;
44 | $this->targetType = $targetType;
45 | $this->if = $if;
46 | $this->else = $else;
47 | }
48 |
49 | public function isNegated(): bool
50 | {
51 | return $this->negated;
52 | }
53 |
54 | public function getSubjectType(): Type
55 | {
56 | return $this->subjectType;
57 | }
58 |
59 | public function getTargetType(): Type
60 | {
61 | return $this->targetType;
62 | }
63 |
64 | public function getIf(): Type
65 | {
66 | return $this->if;
67 | }
68 |
69 | public function getElse(): Type
70 | {
71 | return $this->else;
72 | }
73 |
74 | public function underlyingType(): Type
75 | {
76 | return new Mixed_();
77 | }
78 |
79 | public function __toString(): string
80 | {
81 | return sprintf(
82 | '(%s %s %s ? %s : %s)',
83 | (string) $this->subjectType,
84 | $this->negated ? 'is not' : 'is',
85 | (string) $this->targetType,
86 | (string) $this->if,
87 | (string) $this->else
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/docs/upgrade-v1-to-v2.rst:
--------------------------------------------------------------------------------
1 | ====================
2 | Upgrade to Version 2
3 | ====================
4 |
5 | Version 2 of the Type Resolver introduces several breaking changes and new features. This guide will help you
6 | upgrade your codebase to be compatible with the latest version. The usage of the TypeResolver remains the same. However,
7 | some classes have been moved or replaced, and the minimum PHP version requirement has been raised.
8 |
9 | PHP Version
10 | -----------
11 |
12 | Version 2 requires PHP 7.4 or higher. We have been supporting PHP 7.3 in version 1, but due to changing constraints
13 | in our dependencies, we have had to raise the minimum PHP version. At the moment of writing this, PHP 7.3 is used by 2%
14 | of all installations of this package according to Packagist. We believe this is a reasonable trade-off to ensure we
15 | can continue to deliver new features and improvements.
16 |
17 | Moved classes
18 | -------------
19 |
20 | - ``phpDocumentor\Reflection\Types\InterfaceString`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\InterfaceString`
21 | - ``phpDocumentor\Reflection\Types\ClassString`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\ClassString`
22 | - ``phpDocumentor\Reflection\Types\ArrayKey`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\ArrayKey`
23 | - ``phpDocumentor\Reflection\Types\True_`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\True_`
24 | - ``phpDocumentor\Reflection\Types\False_`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\False_`
25 |
26 | Replaced classes
27 | -----------------
28 |
29 | - ``phpDocumentor\Reflection\Types\Collection`` => :php:class:`phpDocumentor\Reflection\PseudoTypes\Generic`
30 |
31 | Since the introduction of generics in PHP this library was not capable of parsing them correctly. The old Collection
32 | was blocking the use of generics. The new Generic type is a representation of generics like supported in the eco system.
33 |
34 | Changed implementations
35 | -----------------------
36 |
37 | :php:class:`phpDocumentor\Reflection\PseudoTypes\InterfaceString`, :php:class:`phpDocumentor\Reflection\PseudoTypes\ClassString` and
38 | :php:class:`phpDocumentor\Reflection\PseudoTypes\TraitString` are no longer returning a :php:class:`phpDocumentor\Reflection\Fqsen` since
39 | support for generics these classes can have type arguments like any other generic.
40 |
41 |
--------------------------------------------------------------------------------
/src/PseudoTypes/ConditionalForParameter.php:
--------------------------------------------------------------------------------
1 | negated = $negated;
43 | $this->parameterName = $parameterName;
44 | $this->targetType = $targetType;
45 | $this->if = $if;
46 | $this->else = $else;
47 | }
48 |
49 | public function isNegated(): bool
50 | {
51 | return $this->negated;
52 | }
53 |
54 | public function getParameterName(): string
55 | {
56 | return $this->parameterName;
57 | }
58 |
59 | public function getTargetType(): Type
60 | {
61 | return $this->targetType;
62 | }
63 |
64 | public function getIf(): Type
65 | {
66 | return $this->if;
67 | }
68 |
69 | public function getElse(): Type
70 | {
71 | return $this->else;
72 | }
73 |
74 | public function underlyingType(): Type
75 | {
76 | return new Mixed_();
77 | }
78 |
79 | public function __toString(): string
80 | {
81 | return sprintf(
82 | '(%s %s %s ? %s : %s)',
83 | '$' . $this->parameterName,
84 | $this->negated ? 'is not' : 'is',
85 | (string) $this->targetType,
86 | (string) $this->if,
87 | (string) $this->else
88 | );
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/Types/AbstractList.php:
--------------------------------------------------------------------------------
1 | defaultValueType = new Mixed_();
43 | $this->valueType = $valueType;
44 | $this->defaultKeyType = new Compound([new String_(), new Integer()]);
45 | $this->keyType = $keyType;
46 | }
47 |
48 | public function getOriginalKeyType(): ?Type
49 | {
50 | return $this->keyType;
51 | }
52 |
53 | public function getOriginalValueType(): ?Type
54 | {
55 | return $this->valueType;
56 | }
57 |
58 | /**
59 | * Returns the type for the keys of this array.
60 | */
61 | public function getKeyType(): Type
62 | {
63 | return $this->keyType ?? $this->defaultKeyType;
64 | }
65 |
66 | /**
67 | * Returns the type for the values of this array.
68 | */
69 | public function getValueType(): Type
70 | {
71 | return $this->valueType ?? $this->defaultValueType;
72 | }
73 |
74 | /**
75 | * Returns a rendered output of the Type as it would be used in a DocBlock.
76 | */
77 | public function __toString(): string
78 | {
79 | if ($this->valueType === null) {
80 | return 'array';
81 | }
82 |
83 | if ($this->keyType) {
84 | return 'array<' . $this->keyType . ', ' . $this->valueType . '>';
85 | }
86 |
87 | if ($this->valueType instanceof Compound) {
88 | return '(' . $this->valueType . ')[]';
89 | }
90 |
91 | return $this->valueType . '[]';
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/FqsenResolver.php:
--------------------------------------------------------------------------------
1 | isFqsen($fqsen)) {
40 | return new Fqsen($fqsen);
41 | }
42 |
43 | return $this->resolvePartialStructuralElementName($fqsen, $context);
44 | }
45 |
46 | /**
47 | * Tests whether the given type is a Fully Qualified Structural Element Name.
48 | */
49 | private function isFqsen(string $type): bool
50 | {
51 | return strpos($type, self::OPERATOR_NAMESPACE) === 0;
52 | }
53 |
54 | /**
55 | * Resolves a partial Structural Element Name (i.e. `Reflection\DocBlock`) to its FQSEN representation
56 | * (i.e. `\phpDocumentor\Reflection\DocBlock`) based on the Namespace and aliases mentioned in the Context.
57 | *
58 | * @throws InvalidArgumentException When type is not a valid FQSEN.
59 | */
60 | private function resolvePartialStructuralElementName(string $type, Context $context): Fqsen
61 | {
62 | $typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2);
63 |
64 | $namespaceAliases = $context->getNamespaceAliases();
65 |
66 | // if the first segment is not an alias; prepend namespace name and return
67 | if (!isset($namespaceAliases[$typeParts[0]])) {
68 | $namespace = $context->getNamespace();
69 | if ($namespace !== '') {
70 | $namespace .= self::OPERATOR_NAMESPACE;
71 | }
72 |
73 | return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type);
74 | }
75 |
76 | $typeParts[0] = $namespaceAliases[$typeParts[0]];
77 |
78 | return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Types/Context.php:
--------------------------------------------------------------------------------
1 | Fully Qualified Namespace.
43 | * @psalm-var array
44 | */
45 | private $namespaceAliases;
46 |
47 | /**
48 | * Initializes the new context and normalizes all passed namespaces to be in Qualified Namespace Name (QNN)
49 | * format (without a preceding `\`).
50 | *
51 | * @param string $namespace The namespace where this DocBlock resides in.
52 | * @param string[] $namespaceAliases List of namespace aliases => Fully Qualified Namespace.
53 | * @psalm-param array $namespaceAliases
54 | */
55 | public function __construct(string $namespace, array $namespaceAliases = [])
56 | {
57 | $this->namespace = $namespace !== 'global' && $namespace !== 'default'
58 | ? trim($namespace, '\\')
59 | : '';
60 |
61 | foreach ($namespaceAliases as $alias => $fqnn) {
62 | if ($fqnn[0] === '\\') {
63 | $fqnn = substr($fqnn, 1);
64 | }
65 |
66 | if ($fqnn[strlen($fqnn) - 1] === '\\') {
67 | $fqnn = substr($fqnn, 0, -1);
68 | }
69 |
70 | $namespaceAliases[$alias] = $fqnn;
71 | }
72 |
73 | $this->namespaceAliases = $namespaceAliases;
74 | }
75 |
76 | /**
77 | * Returns the Qualified Namespace Name (thus without `\` in front) where the associated element is in.
78 | */
79 | public function getNamespace(): string
80 | {
81 | return $this->namespace;
82 | }
83 |
84 | /**
85 | * Returns a list of Qualified Namespace Names (thus without `\` in front) that are imported, the keys represent
86 | * the alias for the imported Namespace.
87 | *
88 | * @return string[]
89 | * @psalm-return array
90 | */
91 | public function getNamespaceAliases(): array
92 | {
93 | return $this->namespaceAliases;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Types/AggregatedType.php:
--------------------------------------------------------------------------------
1 |
30 | */
31 | abstract class AggregatedType implements Type, IteratorAggregate
32 | {
33 | /**
34 | * @psalm-allow-private-mutation
35 | * @var array
36 | */
37 | private $types = [];
38 |
39 | /** @var string */
40 | private $token;
41 |
42 | /**
43 | * @param array $types
44 | */
45 | public function __construct(array $types, string $token)
46 | {
47 | foreach ($types as $type) {
48 | $this->add($type);
49 | }
50 |
51 | $this->token = $token;
52 | }
53 |
54 | /**
55 | * Returns the type at the given index.
56 | */
57 | public function get(int $index): ?Type
58 | {
59 | if (!$this->has($index)) {
60 | return null;
61 | }
62 |
63 | return $this->types[$index];
64 | }
65 |
66 | /**
67 | * Tests if this compound type has a type with the given index.
68 | */
69 | public function has(int $index): bool
70 | {
71 | return array_key_exists($index, $this->types);
72 | }
73 |
74 | /**
75 | * Tests if this compound type contains the given type.
76 | */
77 | public function contains(Type $type): bool
78 | {
79 | foreach ($this->types as $typePart) {
80 | // if the type is duplicate; do not add it
81 | if ((string) $typePart === (string) $type) {
82 | return true;
83 | }
84 | }
85 |
86 | return false;
87 | }
88 |
89 | /**
90 | * Returns a rendered output of the Type as it would be used in a DocBlock.
91 | */
92 | public function __toString(): string
93 | {
94 | return implode($this->token, $this->types);
95 | }
96 |
97 | /**
98 | * @return ArrayIterator
99 | */
100 | public function getIterator(): ArrayIterator
101 | {
102 | return new ArrayIterator($this->types);
103 | }
104 |
105 | /**
106 | * @psalm-suppress ImpureMethodCall
107 | */
108 | private function add(Type $type): void
109 | {
110 | if ($type instanceof static) {
111 | foreach ($type->getIterator() as $subType) {
112 | $this->add($subType);
113 | }
114 |
115 | return;
116 | }
117 |
118 | // if the type is duplicate; do not add it
119 | if ($this->contains($type)) {
120 | return;
121 | }
122 |
123 | $this->types[] = $type;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://opensource.org/licenses/MIT)
2 | 
3 | [](https://coveralls.io/github/phpDocumentor/TypeResolver?branch=1.x)
4 | [](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x)
5 | [](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x)
6 | 
7 | 
8 |
9 | TypeResolver and FqsenResolver
10 | ==============================
11 |
12 | The specification on types in DocBlocks (PSR-5) describes various keywords and special constructs
13 | but also how to statically resolve the partial name of a Class into a Fully Qualified Class Name (FQCN).
14 |
15 | PSR-5 also introduces an additional way to describe deeper elements than Classes, Interfaces and Traits
16 | called the Fully Qualified Structural Element Name (FQSEN). Using this it is possible to refer to methods,
17 | properties and class constants but also functions and global constants.
18 |
19 | This package provides two Resolvers that are capable of
20 |
21 | 1. Returning a series of Value Object for given expression while resolving any partial class names, and
22 | 2. Returning an FQSEN object after resolving any partial Structural Element Names into Fully Qualified Structural
23 | Element names.
24 |
25 | ## Installing
26 |
27 | The easiest way to install this library is with [Composer](https://getcomposer.org) using the following command:
28 |
29 | $ composer require phpdocumentor/type-resolver
30 |
31 | ## Examples
32 |
33 | Ready to dive in and don't want to read through all that text below? Just consult the [examples](examples) folder and check which type of action that your want to accomplish.
34 |
35 | ## On Types and Element Names
36 |
37 | This component can be used in one of two ways
38 |
39 | 1. To resolve a Type or
40 | 2. To resolve a Fully Qualified Structural Element Name
41 |
42 | The big difference between these two is in the number of things it can resolve.
43 |
44 | The TypeResolver can resolve:
45 |
46 | - a php primitive or pseudo-primitive such as a string or void (`@var string` or `@return void`).
47 | - a composite such as an array of string (`@var string[]`).
48 | - a compound such as a string or integer (`@var string|integer`).
49 | - an array expression (`@var (string|TypeResolver)[]`)
50 | - an object or interface such as the TypeResolver class (`@var TypeResolver`
51 | or `@var \phpDocumentor\Reflection\TypeResolver`)
52 |
53 | > please note that if you want to pass partial class names that additional steps are necessary, see the
54 | > chapter `Resolving partial classes and FQSENs` for more information.
55 |
56 | Where the FqsenResolver can resolve:
57 |
58 | - Constant expressions (i.e. `@see \MyNamespace\MY_CONSTANT`)
59 | - Function expressions (i.e. `@see \MyNamespace\myFunction()`)
60 | - Class expressions (i.e. `@see \MyNamespace\MyClass`)
61 | - Interface expressions (i.e. `@see \MyNamespace\MyInterface`)
62 | - Trait expressions (i.e. `@see \MyNamespace\MyTrait`)
63 | - Class constant expressions (i.e. `@see \MyNamespace\MyClass::MY_CONSTANT`)
64 | - Property expressions (i.e. `@see \MyNamespace\MyClass::$myProperty`)
65 | - Method expressions (i.e. `@see \MyNamespace\MyClass::myMethod()`)
66 |
67 | ## Resolving a type
68 |
69 | In order to resolve a type you will have to instantiate the class `\phpDocumentor\Reflection\TypeResolver` and call its `resolve` method like this:
70 |
71 | ```php
72 | $typeResolver = new \phpDocumentor\Reflection\TypeResolver();
73 | $type = $typeResolver->resolve('string|integer');
74 | ```
75 |
76 | In this example you will receive a Value Object of class `\phpDocumentor\Reflection\Types\Compound` that has two
77 | elements, one of type `\phpDocumentor\Reflection\Types\String_` and one of type
78 | `\phpDocumentor\Reflection\Types\Integer`.
79 |
80 | The real power of this resolver is in its capability to expand partial class names into fully qualified class names; but in order to do that we need an additional `\phpDocumentor\Reflection\Types\Context` class that will inform the resolver in which namespace the given expression occurs and which namespace aliases (or imports) apply.
81 |
82 | ### Resolving nullable types
83 |
84 | Php 7.1 introduced nullable types e.g. `?string`. Type resolver will resolve the original type without the nullable notation `?`
85 | just like it would do without the `?`. After that the type is wrapped in a `\phpDocumentor\Reflection\Types\Nullable` object.
86 | The `Nullable` type has a method to fetch the actual type.
87 |
88 | ## Resolving an FQSEN
89 |
90 | A Fully Qualified Structural Element Name is a reference to another element in your code bases and can be resolved using the `\phpDocumentor\Reflection\FqsenResolver` class' `resolve` method, like this:
91 |
92 | ```php
93 | $fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
94 | $fqsen = $fqsenResolver->resolve('\phpDocumentor\Reflection\FqsenResolver::resolve()');
95 | ```
96 |
97 | In this example we resolve a Fully Qualified Structural Element Name (meaning that it includes the full namespace, class name and element name) and receive a Value Object of type `\phpDocumentor\Reflection\Fqsen`.
98 |
99 | The real power of this resolver is in its capability to expand partial element names into Fully Qualified Structural Element Names; but in order to do that we need an additional `\phpDocumentor\Reflection\Types\Context` class that will inform the resolver in which namespace the given expression occurs and which namespace aliases (or imports) apply.
100 |
101 | ## Resolving partial Classes and Structural Element Names
102 |
103 | Perhaps the best feature of this library is that it knows how to resolve partial class names into fully qualified class names.
104 |
105 | For example, you have this file:
106 |
107 | ```php
108 | namespace My\Example;
109 |
110 | use phpDocumentor\Reflection\Types;
111 |
112 | class Classy
113 | {
114 | /**
115 | * @var Types\Context
116 | * @see Classy::otherFunction()
117 | */
118 | public function __construct($context) {}
119 |
120 | public function otherFunction(){}
121 | }
122 | ```
123 |
124 | Suppose that you would want to resolve (and expand) the type in the `@var` tag and the element name in the `@see` tag.
125 |
126 | For the resolvers to know how to expand partial names you have to provide a bit of _Context_ for them by instantiating a new class named `\phpDocumentor\Reflection\Types\Context` with the name of the namespace and the aliases that are in play.
127 |
128 | ### Creating a Context
129 |
130 | You can do this by manually creating a Context like this:
131 |
132 | ```php
133 | $context = new \phpDocumentor\Reflection\Types\Context(
134 | '\My\Example',
135 | [ 'Types' => '\phpDocumentor\Reflection\Types']
136 | );
137 | ```
138 |
139 | Or by using the `\phpDocumentor\Reflection\Types\ContextFactory` to instantiate a new context based on a Reflector object or by providing the namespace that you'd like to extract and the source code of the file in which the given type expression occurs.
140 |
141 | ```php
142 | $contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
143 | $context = $contextFactory->createFromReflector(new ReflectionMethod('\My\Example\Classy', '__construct'));
144 | ```
145 |
146 | or
147 |
148 | ```php
149 | $contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
150 | $context = $contextFactory->createForNamespace('\My\Example', file_get_contents('My/Example/Classy.php'));
151 | ```
152 |
153 | ### Using the Context
154 |
155 | After you have obtained a Context it is just a matter of passing it along with the `resolve` method of either Resolver class as second argument and the Resolvers will take this into account when resolving partial names.
156 |
157 | To obtain the resolved class name for the `@var` tag in the example above you can do:
158 |
159 | ```php
160 | $typeResolver = new \phpDocumentor\Reflection\TypeResolver();
161 | $type = $typeResolver->resolve('Types\Context', $context);
162 | ```
163 |
164 | When you do this you will receive an object of class `\phpDocumentor\Reflection\Types\Object_` for which you can call the `getFqsen` method to receive a Value Object that represents the complete FQSEN. So that would be `phpDocumentor\Reflection\Types\Context`.
165 |
166 | > Why is the FQSEN wrapped in another object `Object_`?
167 | >
168 | > The resolve method of the TypeResolver only returns object with the interface `Type` and the FQSEN is a common type that does not represent a Type. Also: in some cases a type can represent an "Untyped Object", meaning that it is an object (signified by the `object` keyword) but does not refer to a specific element using an FQSEN.
169 |
170 | Another example is on how to resolve the FQSEN of a method as can be seen with the `@see` tag in the example above. To resolve that you can do the following:
171 |
172 | ```php
173 | $fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
174 | $type = $fqsenResolver->resolve('Classy::otherFunction()', $context);
175 | ```
176 |
177 | Because Classy is a Class in the current namespace its FQSEN will have the `My\Example` namespace and by calling the `resolve` method of the FQSEN Resolver you will receive an `Fqsen` object that refers to `\My\Example\Classy::otherFunction()`.
178 |
--------------------------------------------------------------------------------
/src/Types/ContextFactory.php:
--------------------------------------------------------------------------------
1 | $reflector */
86 |
87 | return $this->createFromReflectionClass($reflector);
88 | }
89 |
90 | if ($reflector instanceof ReflectionParameter) {
91 | return $this->createFromReflectionParameter($reflector);
92 | }
93 |
94 | if ($reflector instanceof ReflectionMethod) {
95 | return $this->createFromReflectionMethod($reflector);
96 | }
97 |
98 | if ($reflector instanceof ReflectionProperty) {
99 | return $this->createFromReflectionProperty($reflector);
100 | }
101 |
102 | if ($reflector instanceof ReflectionClassConstant) {
103 | return $this->createFromReflectionClassConstant($reflector);
104 | }
105 |
106 | throw new UnexpectedValueException('Unhandled \Reflector instance given: ' . get_class($reflector));
107 | }
108 |
109 | private function createFromReflectionParameter(ReflectionParameter $parameter): Context
110 | {
111 | $class = $parameter->getDeclaringClass();
112 | if (!$class) {
113 | throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName());
114 | }
115 |
116 | return $this->createFromReflectionClass($class);
117 | }
118 |
119 | private function createFromReflectionMethod(ReflectionMethod $method): Context
120 | {
121 | $class = $method->getDeclaringClass();
122 |
123 | return $this->createFromReflectionClass($class);
124 | }
125 |
126 | private function createFromReflectionProperty(ReflectionProperty $property): Context
127 | {
128 | $class = $property->getDeclaringClass();
129 |
130 | return $this->createFromReflectionClass($class);
131 | }
132 |
133 | private function createFromReflectionClassConstant(ReflectionClassConstant $constant): Context
134 | {
135 | //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
136 | /** @phpstan-var ReflectionClass