├── .phpunit.result.cache ├── LICENSE ├── composer.json ├── phpcs.xml └── src ├── PhpdocException.php ├── PhpdocParser.php ├── PredefinedSetInterface.php ├── Set └── PhpDocumentor.php ├── Tag ├── AbstractArrayTag.php ├── AbstractTag.php ├── ArrayTag.php ├── CustomTag.php ├── DescriptionTag.php ├── FlagTag.php ├── MapTag.php ├── ModifyTag.php ├── MultiTag.php ├── NumberTag.php ├── PhpDocumentor │ ├── ExampleTag.php │ ├── MethodTag.php │ ├── TypeTag.php │ └── VarTag.php ├── ProxyTagInterface.php ├── RegExpTag.php ├── Summery.php └── WordTag.php ├── TagInterface.php └── TagSet.php /.phpunit.result.cache: -------------------------------------------------------------------------------- 1 | {"version":1,"defects":{"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetTypeInvalid":4,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidInt":4,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidFloat":4,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidType":3,"Jasny\\PhpdocParser\\Tests\\Tag\\CustomTagTest::testProcess":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetTypeInvalid":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidNoKey":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidBlankKey":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidInt":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidFloat":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidType":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessLogicException":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessKeyUnkonwn":4,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessKeyDuplicate":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #0":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #1":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #2":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #3":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #4":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #5":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #6":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #7":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #8":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #9":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #10":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #11":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #12":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #13":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #14":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #15":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #16":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #17":4,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #18":4,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set #0":3,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set #1":3,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcessException with data set #0":3,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcessException with data set #1":3,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcessEmptyValue":3,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testProcessException":4,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #5":3,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #6":3,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testIteration":4,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetGetNonExistent":4,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetSet":4,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetUnset":4,"Error":4},"times":{"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testParseFlag":0.006,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testParseFlagSeveral":0.001,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testParseValue":0.001,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testParseMultiple":0.001,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testParseFull":0.001,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testSummery":0,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testCallback":0.001,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::testMultiline":0,"Jasny\\PhpdocParser\\Tests\\PhpdocParserTest::test":0,"Jasny\\PhpdocParser\\Tests\\Set\\PhpDocumentorTest::testTags":0.001,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testConstruct":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetTypeDefault":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetType with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetType with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetType with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testGetTypeInvalid":0.001,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessParenthesis":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessEmpy":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessQuoted":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessQuotedParenthesis":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessSkip":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessString":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInt":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessFloat":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidInt":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidFloat":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ArrayTagTest::testProcessInvalidType":0,"Jasny\\PhpdocParser\\Tests\\Tag\\CustomTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\CustomTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\DescriptionTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\DescriptionTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\FlagTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\FlagTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\FlagTagTest::testProcessDescription":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetTypeDefault":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetType with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetType with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetType with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testGetTypeInvalid":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessParenthesis":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessEmpy":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessQuoted":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessQuotedParenthesis":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessSkip":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessString":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessAssocInt":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessAssocFloat":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidNoKey":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidBlankKey":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidInt":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidFloat":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MapTagTest::testProcessInvalidType":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ModifyTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ModifyTagTest::testGetTag":0,"Jasny\\PhpdocParser\\Tests\\Tag\\ModifyTagTest::testProcess":0.001,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testGetKey":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testGetTag":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessLogicException":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessKey":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessKeyUnkonwn":0,"Jasny\\PhpdocParser\\Tests\\Tag\\MultiTagTest::testProcessKeyDuplicate":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #5":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #6":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #7":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #8":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #9":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #10":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #11":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #12":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #13":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #14":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #15":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #16":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #17":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstruct with data set #18":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstructException with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstructException with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstructException with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testConstructException with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcess with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcess with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcessException with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcessException with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcessException with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcessException with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\NumberTagTest::testProcessException with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #5":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set #6":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcessException with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\MethodTagTest::testProcessException with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcess with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcess with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\TypeTagTest::testProcessEmptyValue":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testGetAdditionalProperties":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testProcess with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\VarTagTest::testProcess with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testGetRegExp":0,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\RegExpTagTest::testProcessException":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #1":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #2":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #3":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #4":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #5":0,"Jasny\\PhpdocParser\\Tests\\Tag\\SummeryTest::testProcess with data set #6":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testGetDefault":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testGetDefaultUnspecified":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testGetName":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testProcess":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testProcessDefault":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testProcessSentence":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testProcessQuote with data set #0":0,"Jasny\\PhpdocParser\\Tests\\Tag\\WordTagTest::testProcessQuote with data set #1":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testIteration":0.001,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testWithTagSet":0.001,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testWithArray":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testWithout":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testWithoutMultiple":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetExists":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetGet":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetGetNonExistent":0.001,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetSet":0,"Jasny\\PhpdocParser\\Tests\\TagSetTest::testOffsetUnset":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set \"@example some_dir\/and_file.php\"":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set \"@example some_dir\/and_file.php 47\"":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess with data set \"@example some_dir\/and_file.php 47 39\"":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcess":0,"Error":0.001,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set \"blank\"":0,"Jasny\\PhpdocParser\\Tests\\Tag\\PhpDocumentor\\ExampleTagTest::testProcessException with data set \"unclosed quote\"":0}} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jasny 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jasny/phpdoc-parser", 3 | "description": "Jasny skeleton library", 4 | "license": "MIT", 5 | "type": "library", 6 | "authors": [ 7 | { 8 | "name": "Arnold Daniels", 9 | "email": "arnold@jasny.net", 10 | "homepage": "http://www.jasny.net" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/jasny/phpdoc-parser/issues", 15 | "source": "https://github.com/jasny/phpdoc-parser" 16 | }, 17 | "require": { 18 | "php": ">=7.4.0", 19 | "jasny/php-functions": "^3.3" 20 | }, 21 | "require-dev": { 22 | "jasny/php-code-quality": "~2.7.0", 23 | "phpunit/phpunit": ">= 9.0.0" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Jasny\\PhpdocParser\\": "src/" 28 | } 29 | }, 30 | "autoload-dev": { 31 | "psr-4": { 32 | "Jasny\\PhpdocParser\\Tests\\": "tests/" 33 | } 34 | }, 35 | "scripts": { 36 | "test": [ 37 | "phpstan analyse", 38 | "phpunit --testdox --colors=always", 39 | "phpcs -p src" 40 | ] 41 | }, 42 | "config": { 43 | "preferred-install": "dist", 44 | "sort-packages": true, 45 | "optimize-autoloader": true 46 | }, 47 | "minimum-stability": "dev", 48 | "prefer-stable": true 49 | } 50 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The Jasny coding standard. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/PhpdocException.php: -------------------------------------------------------------------------------- 1 | tags = $tags; 28 | } 29 | 30 | /** 31 | * Parse a PHP doc comment 32 | * 33 | * @param string $doc 34 | * @param callable $callback 35 | * @return array 36 | */ 37 | public function parse(string $doc, ?callable $callback = null): array 38 | { 39 | $notations = []; 40 | $rawNotations = $this->extractNotations($doc); 41 | $rawNotations = $this->joinMultilineNotations($rawNotations); 42 | 43 | foreach ($rawNotations as $item) { 44 | if (!isset($this->tags[$item['tag']])) { 45 | continue; 46 | } 47 | 48 | $notations = $this->tags[$item['tag']]->process($notations, $item['value'] ?? ''); 49 | } 50 | 51 | if (isset($this->tags['summery'])) { 52 | $notations = $this->tags['summery']->process($notations, $doc); 53 | } 54 | 55 | if ($callback !== null) { 56 | $notations = $callback($notations); 57 | } 58 | 59 | return $notations; 60 | } 61 | 62 | 63 | /** 64 | * Extract notation from doc comment 65 | * 66 | * @param string $doc 67 | * @return array 68 | */ 69 | protected function extractNotations(string $doc): array 70 | { 71 | $matches = null; 72 | 73 | $tag = '\s*@(?\S+)(?:\h+(?\S.*?)|\h*)'; 74 | $tagContinue = '(?:\040){2}(?\S.*?)'; 75 | $regex = '/^\s*(?:(?:\/\*)?\*)?(?:' . $tag . '|' . $tagContinue . ')(?:\s*\*\*\/)?\r?$/m'; 76 | 77 | return preg_match_all($regex, $doc, $matches, PREG_SET_ORDER) ? $matches : []; 78 | } 79 | 80 | /** 81 | * Join multiline notations 82 | * 83 | * @param array $rawNotations 84 | * @return array 85 | */ 86 | protected function joinMultilineNotations(array $rawNotations): array 87 | { 88 | $result = []; 89 | $tagsNotations = $this->filterTagsNotations($rawNotations); 90 | 91 | foreach ($tagsNotations as $item) { 92 | if ($item['tag'] !== '') { 93 | $result[] = $item; 94 | } else { 95 | $lastIdx = count($result) - 1; 96 | 97 | if (!isset($result[$lastIdx]['value'])) { 98 | $result[$lastIdx]['value'] = ''; 99 | } 100 | 101 | $result[$lastIdx]['value'] = trim($result[$lastIdx]['value']) 102 | . ' ' . trim($item['multiline_value']); 103 | } 104 | } 105 | 106 | return $result; 107 | } 108 | 109 | /** 110 | * Remove everything that goes before tags 111 | * 112 | * @param array $rawNotations 113 | * @return array 114 | */ 115 | protected function filterTagsNotations(array $rawNotations): array 116 | { 117 | for ($i = 0; $i < count($rawNotations); $i++) { 118 | if ($rawNotations[$i]['tag'] !== '') { 119 | return array_slice($rawNotations, $i); 120 | } 121 | } 122 | 123 | return []; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/PredefinedSetInterface.php: -------------------------------------------------------------------------------- 1 | (?:[^\<]\S*\s+)*[^\<]\S*)?\s*)?(?:\<(?[^\>]+)\>)?/'), 46 | new DescriptionTag('copyright'), 47 | new WordTag('deprecated', true), 48 | new ExampleTag('example'), 49 | new FlagTag('ignore'), 50 | new FlagTag('internal'), 51 | new WordTag('link'), 52 | new MultiTag('methods', new MethodTag('method', $fqsenConvertor), 'name'), 53 | new WordTag('package'), 54 | new MultiTag('params', new VarTag('param', $fqsenConvertor), 'name'), 55 | new MultiTag('properties', new VarTag('property', $fqsenConvertor), 'name'), 56 | new MultiTag( 57 | 'properties', 58 | new VarTag('property-read', $fqsenConvertor, ['read_only' => true]), 59 | 'name' 60 | ), 61 | new MultiTag( 62 | 'properties', 63 | new VarTag('property-write', $fqsenConvertor, ['write_only' => true]), 64 | 'name' 65 | ), 66 | new TypeTag('return', $fqsenConvertor), 67 | self::fqsen(new WordTag('see'), $fqsenConvertor), 68 | new WordTag('since'), 69 | new MultiTag('throws', new TypeTag('throws', $fqsenConvertor)), 70 | new DescriptionTag('todo'), 71 | new TypeTag('uses', $fqsenConvertor), 72 | new TypeTag('used-by', $fqsenConvertor), 73 | new VarTag('var', $fqsenConvertor) 74 | ]); 75 | } 76 | 77 | /** 78 | * Apply FQCN converter if available 79 | * 80 | * @param TagInterface $tag 81 | * @param callable|null $fqsenConvertor 82 | * @return TagInterface 83 | */ 84 | protected static function fqsen(TagInterface $tag, ?callable $fqsenConvertor): TagInterface 85 | { 86 | return isset($fqsenConvertor) ? new ModifyTag($tag, $fqsenConvertor) : $tag; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Tag/AbstractArrayTag.php: -------------------------------------------------------------------------------- 1 | type = $type; 37 | } 38 | 39 | /** 40 | * Get the value type 41 | * 42 | * @return string ('string', 'int', 'float') 43 | */ 44 | public function getType(): string 45 | { 46 | return $this->type; 47 | } 48 | 49 | /** 50 | * Process the notation 51 | * 52 | * @param array $notations 53 | * @param string $value 54 | * @return array 55 | */ 56 | public function process(array $notations, string $value): array 57 | { 58 | if ($value === '') { 59 | $notations[$this->name] = []; 60 | 61 | return $notations; 62 | } 63 | 64 | $itemString = $this->stripParentheses($value); 65 | 66 | $items = $this->splitValue($itemString); 67 | 68 | try { 69 | $array = $this->toArray($items); 70 | } catch (PhpdocException $exception) { 71 | throw new PhpdocException( 72 | "Failed to parse '@{$this->name} {$value}': " . $exception->getMessage(), 73 | 0, 74 | $exception 75 | ); 76 | } 77 | 78 | $notations[$this->name] = $array; 79 | 80 | return $notations; 81 | } 82 | 83 | /** 84 | * Strip parentheses from value 85 | * 86 | * @param string $value 87 | * @return null|string|string[] 88 | */ 89 | protected function stripParentheses(string $value) 90 | { 91 | return str_starts_with($value, '(') 92 | ? preg_replace('/^\(((?:"(?:[^"]++|\\\\.)*"|\'(?:[^\']++|\\\\.)*\'|[^\)]++|\))*)\).*$/', '$1', $value) 93 | : $value; 94 | } 95 | 96 | /** 97 | * Split value into items. 98 | * 99 | * @param string $value 100 | * @return array 101 | */ 102 | abstract protected function splitValue(string $value): array; 103 | 104 | 105 | /** 106 | * Get regular expression to extract the value 107 | * 108 | * @return string 109 | * @throws \UnexpectedValueException 110 | */ 111 | protected function getExtractValueRegex(): string 112 | { 113 | switch ($this->type) { 114 | case 'string': 115 | return '/^\s*(["\']?)(?.*)\1\s*$/'; 116 | case 'int': 117 | return '/^\s*(?[\-+]?\d+)\s*$/'; 118 | case 'float': 119 | return '/^\s*(?[\-+]?\d+(?:\.\d+)?(?:e\d+)?)\s*$/'; 120 | default: 121 | throw new \UnexpectedValueException("Unknown type '$this->type'"); 122 | } 123 | } 124 | 125 | /** 126 | * Process matched items. 127 | * 128 | * @param array $items 129 | * @return array 130 | */ 131 | protected function toArray(array $items): array 132 | { 133 | $result = []; 134 | 135 | $regex = $this->getExtractValueRegex(); 136 | 137 | foreach ($items as $key => $item) { 138 | if (!preg_match($regex, $item, $matches)) { 139 | throw new PhpdocException("invalid value '" . addcslashes(trim($item), "'") . "'"); 140 | } 141 | 142 | $value = $matches['value']; 143 | settype($value, $this->type); 144 | 145 | if (is_string($key)) { 146 | $key = trim($key, '\'"'); 147 | } 148 | 149 | $result[$key] = $value; 150 | } 151 | 152 | return $result; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/Tag/AbstractTag.php: -------------------------------------------------------------------------------- 1 | name = $name; 27 | } 28 | 29 | /** 30 | * Get the tag name 31 | * 32 | * @return string 33 | */ 34 | public function getName(): string 35 | { 36 | return $this->name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Tag/ArrayTag.php: -------------------------------------------------------------------------------- 1 | process = $process; 28 | } 29 | 30 | /** 31 | * Process a notation. 32 | * 33 | * @param array $notations 34 | * @param string $value 35 | * @return array 36 | */ 37 | public function process(array $notations, string $value): array 38 | { 39 | return call_user_func($this->process, $notations, $value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Tag/DescriptionTag.php: -------------------------------------------------------------------------------- 1 | name] = $value; 22 | 23 | return $notations; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Tag/FlagTag.php: -------------------------------------------------------------------------------- 1 | name] = true; 24 | 25 | return $notations; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Tag/MapTag.php: -------------------------------------------------------------------------------- 1 | ' . $regexpKey . ')\s*=\s*)?(?' . $regexpValue. ')\s*/'; 25 | 26 | preg_match_all($regexp, $value, $matches, PREG_PATTERN_ORDER); // regex can't fail 27 | 28 | $keys = preg_replace('/^\s*(["\']?)(.*?)\1\s*$/', '$2', $matches['key']); 29 | 30 | foreach ($keys as $pos => $key) { 31 | if ($key === '') { 32 | $item = trim($matches['value'][$pos]); 33 | throw new PhpdocException("Failed to parse '@{$this->name} {$value}': no key for value '$item'"); 34 | } 35 | } 36 | 37 | return array_combine($keys, $matches['value']); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Tag/ModifyTag.php: -------------------------------------------------------------------------------- 1 | tag = $tag; 34 | $this->logic = $logic; 35 | } 36 | 37 | /** 38 | * Get the tag name 39 | * 40 | * @return string 41 | */ 42 | public function getName(): string 43 | { 44 | return $this->tag->getName(); 45 | } 46 | 47 | /** 48 | * Get the wrapped tag. 49 | * 50 | * @return TagInterface 51 | */ 52 | public function getTag(): TagInterface 53 | { 54 | return $this->tag; 55 | } 56 | 57 | /** 58 | * Process an notation. 59 | * 60 | * @param array $notations 61 | * @param string $value 62 | * @return array 63 | */ 64 | public function process(array $notations, string $value): array 65 | { 66 | $tagNotations = $this->tag->process([], $value); 67 | $notations = call_user_func($this->logic, $notations, $tagNotations, $value); 68 | 69 | return $notations; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Tag/MultiTag.php: -------------------------------------------------------------------------------- 1 | key = $key; 41 | $this->tag = $tag; 42 | $this->index = $index; 43 | } 44 | 45 | 46 | /** 47 | * Get the notation key. 48 | * 49 | * @return string 50 | */ 51 | public function getKey() 52 | { 53 | return $this->key; 54 | } 55 | 56 | /** 57 | * Get the tag name 58 | * 59 | * @return string 60 | */ 61 | public function getName(): string 62 | { 63 | return $this->tag->getName(); 64 | } 65 | 66 | /** 67 | * Get the representation of a single tag 68 | * 69 | * @return TagInterface 70 | */ 71 | public function getTag(): TagInterface 72 | { 73 | return $this->tag; 74 | } 75 | 76 | /** 77 | * Process an notation. 78 | * 79 | * @param array $notations 80 | * @param string $value 81 | * @return array 82 | * @throws PhpdocException 83 | */ 84 | public function process(array $notations, string $value): array 85 | { 86 | $tagName = $this->tag->getName(); 87 | 88 | $tagNotations = $this->tag->process([], $value); 89 | 90 | if (count($tagNotations) !== 1) { 91 | throw new \LogicException("Unable to parse '@{$tagName}' tag: Multi tags must result in " 92 | . "exactly one notation per tag."); 93 | } 94 | 95 | $this->addNotation($notations, $value, reset($tagNotations)); 96 | 97 | return $notations; 98 | } 99 | 100 | /** 101 | * Add notation. 102 | * 103 | * @param array $notations 104 | * @param string $value 105 | * @param mixed $item 106 | * @return void 107 | * @throws PhpdocException 108 | */ 109 | protected function addNotation(array &$notations, string $value, $item): void 110 | { 111 | if (!isset($this->index)) { 112 | $notations[$this->key][] = $item; 113 | return; 114 | } 115 | 116 | $tagName = $this->getName(); 117 | 118 | if (!is_array($item) || !isset($item[$this->index])) { 119 | throw new PhpdocException("Unable to add '@{$tagName} $value' tag: No {$this->index}"); 120 | } 121 | 122 | $index = $item[$this->index]; 123 | 124 | if (isset($notations[$this->key][$index])) { 125 | throw new PhpdocException("Unable to add '@{$tagName} $value' tag: Duplicate {$this->index} " 126 | . "'$index'"); 127 | } 128 | 129 | $notations[$this->key][$index] = $item; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Tag/NumberTag.php: -------------------------------------------------------------------------------- 1 | $max) { 49 | throw new PhpdocException("Min value (given $min) should be less than max (given $max)"); 50 | } 51 | 52 | parent::__construct($name); 53 | 54 | $this->type = $type; 55 | $this->min = $min; 56 | $this->max = $max; 57 | } 58 | 59 | /** 60 | * Process an notation. 61 | * 62 | * @param array $notations 63 | * @param string $value 64 | * @return array 65 | */ 66 | public function process(array $notations, string $value): array 67 | { 68 | [$word] = explode(' ', $value, 2); 69 | 70 | if (!is_numeric($word)) { 71 | throw new PhpdocException("Failed to parse '@{$this->name} $word': not a number"); 72 | } 73 | 74 | if ($word < $this->min) { 75 | throw new PhpdocException("Parsed value $word should be greater then min value {$this->min}"); 76 | } 77 | 78 | if ($word > $this->max) { 79 | throw new PhpdocException("Parsed value $word should be less then max value {$this->max}"); 80 | } 81 | 82 | if (in_array($this->type, ['int', 'integer'], true)) { 83 | $word = (int)$word; 84 | } 85 | 86 | $notations[$this->name] = $word + 0; 87 | 88 | return $notations; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Tag/PhpDocumentor/ExampleTag.php: -------------------------------------------------------------------------------- 1 | (?:[^"]\S*|"[^"]+"))(?:\s*(?\d+)' 26 | . '(?:\s*(?\d+))?)?(?:\s*(?.+))?/'; 27 | 28 | if (!preg_match($regexp, $value, $matches)) { 29 | throw new PhpdocException("Failed to parse '@{$this->name} $value': invalid syntax"); 30 | } 31 | 32 | $this->normalizeValues($matches); 33 | $matches = array_only($matches, ['location', 'start_line', 'number_of_lines', 'description']); 34 | 35 | $notations[$this->name] = $matches; 36 | 37 | return $notations; 38 | } 39 | 40 | /** 41 | * Normalize parsed values 42 | * 43 | * @param array $values 44 | */ 45 | protected function normalizeValues(array &$values): void 46 | { 47 | $values['location'] = trim($values['location'], '"'); 48 | 49 | foreach (['start_line', 'number_of_lines'] as $name) { 50 | if (!isset($values[$name])) { 51 | continue; 52 | } 53 | 54 | if ($values[$name] === '') { 55 | unset($values[$name]); 56 | } else { 57 | $values[$name] = (int)$values[$name]; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Tag/PhpDocumentor/MethodTag.php: -------------------------------------------------------------------------------- 1 | fqsenConvertor = $fqsenConvertor; 32 | } 33 | 34 | /** 35 | * Process a notation. 36 | * 37 | * @param array $notations 38 | * @param string $value 39 | * @return array 40 | */ 41 | public function process(array $notations, string $value): array 42 | { 43 | $regexp = '/^(?:(?static)\s+)?(?:(?\S+)\s+)?(?\w+)\((?[^\)]+)?\)(?:\s+(?.*))?/'; 44 | 45 | if (!preg_match($regexp, $value, $method)) { 46 | throw new PhpdocException("Failed to parse '@{$this->name} $value': invalid syntax"); 47 | } 48 | 49 | if (isset($method['return_type']) && isset($this->fqsenConvertor)) { 50 | $method['return_type'] = call_user_func($this->fqsenConvertor, $method['return_type']); 51 | } 52 | 53 | if (isset($method['static']) && $method['static'] !== '') { 54 | $method['static'] = true; 55 | } else { 56 | unset($method['static']); 57 | } 58 | 59 | $method['params'] = isset($method['params']) ? $this->processParams($value, $method['params']) : []; 60 | $method = array_only($method, ['static', 'return_type', 'name', 'params', 'description']); 61 | 62 | $notations[$this->name] = $method; 63 | 64 | return $notations; 65 | } 66 | 67 | /** 68 | * Process parameters from method notation 69 | * 70 | * @param string $value Input value 71 | * @param string $raw Parameters string 72 | * @return array 73 | */ 74 | protected function processParams(string $value, string $raw): array 75 | { 76 | $params = []; 77 | $rawParams = preg_split('/\s*,\s*/', $raw); 78 | 79 | $regexp = '/^(?:(?[^$]+)\s+)?\$(?\w+)(?:\s*=\s*(?"[^"]+"|\[[^\]]+\]|[^,]+))?$/'; 80 | 81 | foreach ($rawParams as $rawParam) { 82 | if (!preg_match($regexp, $rawParam, $param)) { 83 | throw new PhpdocException("Failed to parse '@{$this->name} {$value}': invalid syntax"); 84 | } 85 | 86 | $this->processParamType($param); 87 | $this->processParamDefault($param); 88 | 89 | $params[$param['name']] = array_only($param, ['type', 'name', 'default']); 90 | } 91 | 92 | return $params; 93 | } 94 | 95 | /** 96 | * Process type property of parameter 97 | * 98 | * @param array $param 99 | * @return void 100 | */ 101 | protected function processParamType(array &$param): void 102 | { 103 | if (isset($param['type']) && $param['type'] === '') { 104 | unset($param['type']); 105 | } 106 | 107 | if (isset($param['type']) && isset($this->fqsenConvertor)) { 108 | $param['type'] = call_user_func($this->fqsenConvertor, $param['type']); 109 | } 110 | } 111 | 112 | /** 113 | * Process default property of parameter 114 | * 115 | * @param array $param 116 | * @return void 117 | */ 118 | protected function processParamDefault(array &$param): void 119 | { 120 | if (isset($param['default'])) { 121 | $param['default'] = trim($param['default'], '"\''); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Tag/PhpDocumentor/TypeTag.php: -------------------------------------------------------------------------------- 1 | fqsenConvertor = $fqsenConvertor; 32 | } 33 | 34 | /** 35 | * Process a notation. 36 | * 37 | * @param array $notations 38 | * @param string $value 39 | * @return array 40 | */ 41 | public function process(array $notations, string $value): array 42 | { 43 | if ($value === '') { 44 | throw new PhpdocException("Failed to parse '@{$this->name}': tag value should not be empty"); 45 | } 46 | 47 | $match = preg_match('/^(?\S+)(?:\s+(?.*))?/', $value, $data); //regexp won't fail 48 | 49 | $this->processType($data); 50 | $data = array_only($data, ['type', 'description']); 51 | 52 | $notations[$this->name] = $data; 53 | 54 | return $notations; 55 | } 56 | 57 | /** 58 | * Process type parameter 59 | * 60 | * @param array $data 61 | */ 62 | protected function processType(array &$data): void 63 | { 64 | if (isset($data['type']) && $this->fqsenConvertor !== null) { 65 | $data['type'] = call_user_func($this->fqsenConvertor, $data['type']); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Tag/PhpDocumentor/VarTag.php: -------------------------------------------------------------------------------- 1 | fqsenConvertor = $fqsenConvertor; 38 | $this->additional = $additional; 39 | } 40 | 41 | /** 42 | * Get additional properties that are always applied. 43 | * 44 | * @return array 45 | */ 46 | public function getAdditionalProperties(): array 47 | { 48 | return $this->additional; 49 | } 50 | 51 | /** 52 | * Process a notation. 53 | * 54 | * @param array $notations 55 | * @param string $value 56 | * @return array 57 | */ 58 | public function process(array $notations, string $value): array 59 | { 60 | $regexp = '/^(?:(?[^$\s]+)\s*)?(?:\$(?\w+)\s*)?(?:"(?[^"]+)"\s*)?(?:(?.+))?/'; 61 | preg_match($regexp, $value, $props); //regexp won't fail 62 | 63 | $this->removeEmptyValues($props); 64 | 65 | if (isset($props['type']) && isset($this->fqsenConvertor)) { 66 | $props['type'] = call_user_func($this->fqsenConvertor, $props['type']); 67 | } 68 | 69 | $props = array_only($props, ['type', 'name', 'id', 'description']); 70 | 71 | $notations[$this->name] = $props + $this->additional; 72 | 73 | return $notations; 74 | } 75 | 76 | /** 77 | * Remove empty values from parsed data 78 | * 79 | * @param array $props 80 | */ 81 | protected function removeEmptyValues(array &$props): void 82 | { 83 | foreach (['type', 'name', 'id'] as $name) { 84 | if (isset($props[$name]) && $props[$name] === '') { 85 | unset($props[$name]); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Tag/ProxyTagInterface.php: -------------------------------------------------------------------------------- 1 | regexp = $regexp; 31 | } 32 | 33 | /** 34 | * Get the regular expression 35 | * 36 | * @return string 37 | */ 38 | public function getRegExp(): string 39 | { 40 | return $this->regexp; 41 | } 42 | 43 | /** 44 | * Process a notation 45 | * 46 | * @param array $notations 47 | * @param string $value 48 | * @return array 49 | */ 50 | public function process(array $notations, string $value): array 51 | { 52 | if (!preg_match($this->regexp, $value, $matches)) { 53 | throw new PhpdocException("Failed to parse '@{$this->name} $value': invalid syntax"); 54 | } 55 | 56 | $notations[$this->name] = $matches; 57 | 58 | return $notations; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Tag/Summery.php: -------------------------------------------------------------------------------- 1 | default = $default; 34 | } 35 | 36 | /** 37 | * Return default if no value is specified 38 | * 39 | * @return string|bool 40 | */ 41 | public function getDefault() 42 | { 43 | return $this->default; 44 | } 45 | 46 | 47 | /** 48 | * Process a notation. 49 | * 50 | * @param array $notations 51 | * @param string $value 52 | * @return array 53 | */ 54 | public function process(array $notations, string $value): array 55 | { 56 | if ($value === '') { 57 | $notations[$this->name] = $this->default; 58 | return $notations; 59 | } 60 | 61 | $matches = []; 62 | $quoted = in_array($value[0], ['"', '\''], true) && 63 | preg_match('/^(?|"((?:[^"]+|\\\\.)*)"|\'((?:[^\']+|\\\\.)*)\')/', $value, $matches); 64 | 65 | $word = $quoted ? $matches[1] : str_before($value, ' '); 66 | $notations[$this->name] = $word; 67 | 68 | return $notations; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/TagInterface.php: -------------------------------------------------------------------------------- 1 | tags[$tag->getName()] = $tag; 31 | } 32 | } 33 | 34 | /** 35 | * Retrieve an external iterator. 36 | * 37 | * @retrun \ArrayIterator 38 | */ 39 | public function getIterator(): \ArrayIterator 40 | { 41 | return new \ArrayIterator($this->tags); 42 | } 43 | 44 | 45 | /** 46 | * Combine sets. 47 | * 48 | * @param iterable $tags 49 | * @return static 50 | */ 51 | public function with(iterable $tags): self 52 | { 53 | $tagArray = $tags instanceof \Traversable ? iterator_to_array($tags, false) : $tags; 54 | 55 | return new static(array_merge(array_values($this->tags), $tagArray)); 56 | } 57 | 58 | /** 59 | * Get set without specified tag(s) 60 | * 61 | * @param string ...$keys 62 | * @return static 63 | */ 64 | public function without(string ...$keys): self 65 | { 66 | return new static(array_without($this->tags, $keys)); 67 | } 68 | 69 | 70 | /** 71 | * Whether a offset exists. 72 | * 73 | * @param string $key Tag name 74 | * @return bool 75 | */ 76 | public function offsetExists($key): bool 77 | { 78 | return isset($this->tags[$key]); 79 | } 80 | 81 | /** 82 | * Offset to retrieve. 83 | * 84 | * @param mixed $key Tag name 85 | * @return TagInterface 86 | * @throws \OutOfBoundsException if tag is unknown. 87 | */ 88 | public function offsetGet($key): TagInterface 89 | { 90 | if (!isset($this->tags[$key])) { 91 | throw new \OutOfBoundsException("Unknown tag '@{$key}'; Use isset to see if tag is defined."); 92 | } 93 | 94 | return $this->tags[$key]; 95 | } 96 | 97 | /** 98 | * Offset to set. 99 | * 100 | * @param mixed $key 101 | * @param TagInterface $tag The value to set. 102 | * @return void 103 | * @throws \BadMethodCallException 104 | */ 105 | public function offsetSet($key, $tag): void 106 | { 107 | throw new \BadMethodCallException("A tagset is immutable; Use `with()` instead."); 108 | } 109 | 110 | /** 111 | * Offset to unset. 112 | * 113 | * @param string $key Tag name 114 | * @return void 115 | * @throws \BadMethodCallException 116 | */ 117 | public function offsetUnset($key): void 118 | { 119 | throw new \BadMethodCallException("A tagset is immutable; Use `without()` instead."); 120 | } 121 | } 122 | --------------------------------------------------------------------------------