├── .phpdoc └── template │ └── base.html.twig ├── LICENSE ├── README.md ├── composer.json ├── docs ├── getting-started.rst └── index.rst ├── phpdoc.dist.xml └── src ├── FqsenResolver.php ├── PseudoType.php ├── PseudoTypes ├── ArrayShape.php ├── ArrayShapeItem.php ├── CallableString.php ├── ConstExpression.php ├── False_.php ├── FloatValue.php ├── HtmlEscapedString.php ├── IntegerRange.php ├── IntegerValue.php ├── ListShape.php ├── ListShapeItem.php ├── List_.php ├── LiteralString.php ├── LowercaseString.php ├── NegativeInteger.php ├── NonEmptyArray.php ├── NonEmptyList.php ├── NonEmptyLowercaseString.php ├── NonEmptyString.php ├── NumericString.php ├── Numeric_.php ├── ObjectShape.php ├── ObjectShapeItem.php ├── PositiveInteger.php ├── ShapeItem.php ├── StringValue.php ├── TraitString.php └── True_.php ├── Type.php ├── TypeResolver.php └── Types ├── AbstractList.php ├── AggregatedType.php ├── ArrayKey.php ├── Array_.php ├── Boolean.php ├── CallableParameter.php ├── Callable_.php ├── ClassString.php ├── Collection.php ├── Compound.php ├── Context.php ├── ContextFactory.php ├── Expression.php ├── Float_.php ├── Integer.php ├── InterfaceString.php ├── Intersection.php ├── Iterable_.php ├── Mixed_.php ├── Never_.php ├── Null_.php ├── Nullable.php ├── Object_.php ├── Parent_.php ├── Resource_.php ├── Scalar.php ├── Self_.php ├── Static_.php ├── String_.php ├── This.php └── Void_.php /.phpdoc/template/base.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html.twig' %} 2 | 3 | {% set topMenu = { 4 | "menu": [ 5 | { "name": "About", "url": "https://phpdoc.org/"}, 6 | { "name": "Components", "url": "https://phpdoc.org/components.html"}, 7 | { "name": "Documentation", "url": "https://docs.phpdoc.org/"}, 8 | ], 9 | "social": [ 10 | { "iconClass": "fab fa-mastodon", "url": "https://phpc.social/@phpdoc"}, 11 | { "iconClass": "fab fa-github", "url": "https://github.com/phpdocumentor/typeresolver"}, 12 | { "iconClass": "fas fa-envelope-open-text", "url": "https://github.com/orgs/phpDocumentor/discussions"} 13 | ] 14 | } 15 | %} 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | ![](https://github.com/phpdocumentor/typeresolver/workflows/Qa%20workflow/badge.svg?branch=1.x) 3 | [![Coveralls Coverage](https://img.shields.io/coveralls/github/phpDocumentor/TypeResolver.svg)](https://coveralls.io/github/phpDocumentor/TypeResolver?branch=1.x) 4 | [![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/phpDocumentor/TypeResolver.svg)](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x) 5 | [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/phpDocumentor/TypeResolver.svg)](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x) 6 | ![Packagist Version](https://img.shields.io/packagist/v/phpdocumentor/type-resolver?label=Packagist%20stable) 7 | ![Packagist Version](https://img.shields.io/packagist/vpre/phpdocumentor/type-resolver?label=Packagist%20unstable) 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 | -------------------------------------------------------------------------------- /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.3 || ^8.0", 14 | "phpdocumentor/reflection-common": "^2.0", 15 | "phpstan/phpdoc-parser": "^1.18|^2.0", 16 | "doctrine/deprecations": "^1.0" 17 | }, 18 | "require-dev": { 19 | "ext-tokenizer": "*", 20 | "phpunit/phpunit": "^9.5", 21 | "phpstan/phpstan": "^1.8", 22 | "phpstan/phpstan-phpunit": "^1.1", 23 | "phpstan/extension-installer": "^1.1", 24 | "vimeo/psalm": "^4.25", 25 | "rector/rector": "^0.13.9", 26 | "phpbench/phpbench": "^1.2" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "phpDocumentor\\Reflection\\": "src" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "phpDocumentor\\Reflection\\": ["tests/unit", "tests/benchmark"] 36 | } 37 | }, 38 | "extra": { 39 | "branch-alias": { 40 | "dev-1.x": "1.x-dev" 41 | } 42 | }, 43 | "config": { 44 | "platform": { 45 | "php": "7.3.0" 46 | }, 47 | "allow-plugins": { 48 | "phpstan/extension-installer": true 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Type resolver 3 | ============= 4 | 5 | This project part of the phpDocumentor project. It is capable of creating an object structure of the type 6 | specifications found in the PHPDoc blocks of a project. This can be useful for static analysis of a project 7 | or other behavior that requires knowledge of the types used in a project like automatically build forms. 8 | 9 | This project aims to cover all types that are available in PHPDoc and PHP itself. And is open for extension by 10 | third party developers. 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | :hidden: 15 | 16 | index 17 | getting-started 18 | -------------------------------------------------------------------------------- /phpdoc.dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | Type Resolver 9 | 10 | build/docs 11 | 12 | 13 | latest 14 | 15 | 16 | src/ 17 | 18 | api 19 | 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 | guides 42 | 43 | 44 | 45 |