PluginProbe ʕ •ᴥ•ʔ
Cookiebot by Usercentrics – Automatic Cookie Banner for GDPR/CCPA & Google Consent Mode / 3.11.1
Cookiebot by Usercentrics – Automatic Cookie Banner for GDPR/CCPA & Google Consent Mode v3.11.1
4.7.2 4.7.1 trunk 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 3.0.0 3.0.1 3.1.0 3.10.0 3.10.1 3.11.1 3.11.2 3.11.3 3.2.0 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.5 3.6.6 3.7.0 3.7.1 3.8.0 3.9.0 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.2.0 4.2.1 4.2.10 4.2.11 4.2.12 4.2.13 4.2.14 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.3.10 4.3.11 4.3.12 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.7.1 4.3.8 4.3.9 4.3.9.1 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.10 4.5.11 4.5.2 4.5.3 4.5.4 4.5.5 4.5.6 4.5.7 4.5.8 4.5.9 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.6.6 4.6.7 4.7.0
cookiebot / addons / inc / Dependencies / PhpDocReader / PhpParser / TokenParser.php
cookiebot / addons / inc / Dependencies / PhpDocReader / PhpParser Last commit date
TokenParser.php 5 years ago UseStatementParser.php 5 years ago
TokenParser.php
183 lines
1 <?php declare(strict_types=1);
2
3 namespace Cybot\Dependencies\PhpDocReader\PhpParser;
4
5 /**
6 * Parses a file for namespaces/use/class declarations.
7 *
8 * Class taken and adapted from doctrine/annotations to avoid pulling the whole package.
9 *
10 * @author Fabien Potencier <fabien@symfony.com>
11 * @author Christian Kaps <christian.kaps@mohiva.com>
12 */
13 class TokenParser
14 {
15 /**
16 * The token list.
17 *
18 * @var list<mixed[]>
19 */
20 private $tokens;
21
22 /**
23 * The number of tokens.
24 *
25 * @var int
26 */
27 private $numTokens;
28
29 /**
30 * The current array pointer.
31 *
32 * @var int
33 */
34 private $pointer = 0;
35
36 /**
37 * @param string $contents
38 */
39 public function __construct($contents)
40 {
41 $this->tokens = token_get_all($contents);
42
43 // The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it
44 // saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored
45 // doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a
46 // docblock. If the first thing in the file is a class without a doc block this would cause calls to
47 // getDocBlock() on said class to return our long lost doc_comment. Argh.
48 // To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least
49 // it's harmless to us.
50 token_get_all("<?php\n/**\n *\n */");
51
52 $this->numTokens = count($this->tokens);
53 }
54
55 /**
56 * Gets all use statements.
57 *
58 * @param string $namespaceName The namespace name of the reflected class.
59 *
60 * @return array<string, string> A list with all found use statements.
61 */
62 public function parseUseStatements($namespaceName)
63 {
64 $statements = [];
65 while (($token = $this->next())) {
66 if ($token[0] === T_USE) {
67 $statements = array_merge($statements, $this->parseUseStatement());
68 continue;
69 }
70
71 if ($token[0] !== T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {
72 continue;
73 }
74
75 // Get fresh array for new namespace. This is to prevent the parser to collect the use statements
76 // for a previous namespace with the same name. This is the case if a namespace is defined twice
77 // or if a namespace with the same name is commented out.
78 $statements = [];
79 }
80
81 return $statements;
82 }
83
84 /**
85 * Gets the next non whitespace and non comment token.
86 *
87 * @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
88 * If FALSE then only whitespace and normal comments are skipped.
89 *
90 * @return mixed[]|string|null The token if exists, null otherwise.
91 */
92 private function next($docCommentIsComment = true)
93 {
94 for ($i = $this->pointer; $i < $this->numTokens; $i++) {
95 $this->pointer++;
96 if (
97 $this->tokens[$i][0] === T_WHITESPACE ||
98 $this->tokens[$i][0] === T_COMMENT ||
99 ($docCommentIsComment && $this->tokens[$i][0] === T_DOC_COMMENT)
100 ) {
101 continue;
102 }
103
104 return $this->tokens[$i];
105 }
106
107 return null;
108 }
109
110 /**
111 * Parses a single use statement.
112 *
113 * @return array<string, string> A list with all found class names for a use statement.
114 */
115 private function parseUseStatement()
116 {
117 $groupRoot = '';
118 $class = '';
119 $alias = '';
120 $statements = [];
121 $explicitAlias = false;
122 while (($token = $this->next())) {
123 if (! $explicitAlias && $token[0] === T_STRING) {
124 $class .= $token[1];
125 $alias = $token[1];
126 } elseif ($explicitAlias && $token[0] === T_STRING) {
127 $alias = $token[1];
128 } elseif (
129 PHP_VERSION_ID >= 80000 &&
130 ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
131 ) {
132 $class .= $token[1];
133
134 $classSplit = explode('\\', $token[1]);
135 $alias = $classSplit[count($classSplit) - 1];
136 } elseif ($token[0] === T_NS_SEPARATOR) {
137 $class .= '\\';
138 $alias = '';
139 } elseif ($token[0] === T_AS) {
140 $explicitAlias = true;
141 $alias = '';
142 } elseif ($token === ',') {
143 $statements[strtolower($alias)] = $groupRoot . $class;
144 $class = '';
145 $alias = '';
146 $explicitAlias = false;
147 } elseif ($token === ';') {
148 $statements[strtolower($alias)] = $groupRoot . $class;
149 break;
150 } elseif ($token === '{') {
151 $groupRoot = $class;
152 $class = '';
153 } elseif ($token === '}') {
154 continue;
155 } else {
156 break;
157 }
158 }
159
160 return $statements;
161 }
162
163 /**
164 * Gets the namespace.
165 *
166 * @return string The found namespace.
167 */
168 private function parseNamespace()
169 {
170 $name = '';
171 while (
172 ($token = $this->next()) && ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR || (
173 PHP_VERSION_ID >= 80000 &&
174 ($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
175 ))
176 ) {
177 $name .= $token[1];
178 }
179
180 return $name;
181 }
182 }
183