PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / prefixed / php-di / phpdoc-reader / src / PhpDocReader / PhpParser / TokenParser.php
matomo / app / vendor / prefixed / php-di / phpdoc-reader / src / PhpDocReader / PhpParser Last commit date
TokenParser.php 1 year ago UseStatementParser.php 1 year ago
TokenParser.php
155 lines
1 <?php
2
3 declare (strict_types=1);
4 namespace Matomo\Dependencies\PhpDocReader\PhpParser;
5
6 /**
7 * Parses a file for namespaces/use/class declarations.
8 *
9 * Class taken and adapted from doctrine/annotations to avoid pulling the whole package.
10 *
11 * @author Fabien Potencier <fabien@symfony.com>
12 * @author Christian Kaps <christian.kaps@mohiva.com>
13 */
14 class TokenParser
15 {
16 /**
17 * The token list.
18 *
19 * @var list<mixed[]>
20 */
21 private $tokens;
22 /**
23 * The number of tokens.
24 *
25 * @var int
26 */
27 private $numTokens;
28 /**
29 * The current array pointer.
30 *
31 * @var int
32 */
33 private $pointer = 0;
34 /**
35 * @param string $contents
36 */
37 public function __construct($contents)
38 {
39 $this->tokens = token_get_all($contents);
40 // The PHP parser sets internal compiler globals for certain things. Annoyingly, the last docblock comment it
41 // saw gets stored in doc_comment. When it comes to compile the next thing to be include()d this stored
42 // doc_comment becomes owned by the first thing the compiler sees in the file that it considers might have a
43 // docblock. If the first thing in the file is a class without a doc block this would cause calls to
44 // getDocBlock() on said class to return our long lost doc_comment. Argh.
45 // To workaround, cause the parser to parse an empty docblock. Sure getDocBlock() will return this, but at least
46 // it's harmless to us.
47 token_get_all("<?php\n/**\n *\n */");
48 $this->numTokens = count($this->tokens);
49 }
50 /**
51 * Gets all use statements.
52 *
53 * @param string $namespaceName The namespace name of the reflected class.
54 *
55 * @return array<string, string> A list with all found use statements.
56 */
57 public function parseUseStatements($namespaceName)
58 {
59 $statements = [];
60 while ($token = $this->next()) {
61 if ($token[0] === \T_USE) {
62 $statements = array_merge($statements, $this->parseUseStatement());
63 continue;
64 }
65 if ($token[0] !== \T_NAMESPACE || $this->parseNamespace() !== $namespaceName) {
66 continue;
67 }
68 // Get fresh array for new namespace. This is to prevent the parser to collect the use statements
69 // for a previous namespace with the same name. This is the case if a namespace is defined twice
70 // or if a namespace with the same name is commented out.
71 $statements = [];
72 }
73 return $statements;
74 }
75 /**
76 * Gets the next non whitespace and non comment token.
77 *
78 * @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped.
79 * If FALSE then only whitespace and normal comments are skipped.
80 *
81 * @return mixed[]|string|null The token if exists, null otherwise.
82 */
83 private function next($docCommentIsComment = \true)
84 {
85 for ($i = $this->pointer; $i < $this->numTokens; $i++) {
86 $this->pointer++;
87 if ($this->tokens[$i][0] === \T_WHITESPACE || $this->tokens[$i][0] === \T_COMMENT || $docCommentIsComment && $this->tokens[$i][0] === \T_DOC_COMMENT) {
88 continue;
89 }
90 return $this->tokens[$i];
91 }
92 return null;
93 }
94 /**
95 * Parses a single use statement.
96 *
97 * @return array<string, string> A list with all found class names for a use statement.
98 */
99 private function parseUseStatement()
100 {
101 $groupRoot = '';
102 $class = '';
103 $alias = '';
104 $statements = [];
105 $explicitAlias = \false;
106 while ($token = $this->next()) {
107 if (!$explicitAlias && $token[0] === \T_STRING) {
108 $class .= $token[1];
109 $alias = $token[1];
110 } elseif ($explicitAlias && $token[0] === \T_STRING) {
111 $alias = $token[1];
112 } elseif (\PHP_VERSION_ID >= 80000 && ($token[0] === \T_NAME_QUALIFIED || $token[0] === \T_NAME_FULLY_QUALIFIED)) {
113 $class .= $token[1];
114 $classSplit = explode('\\', $token[1]);
115 $alias = $classSplit[count($classSplit) - 1];
116 } elseif ($token[0] === \T_NS_SEPARATOR) {
117 $class .= '\\';
118 $alias = '';
119 } elseif ($token[0] === \T_AS) {
120 $explicitAlias = \true;
121 $alias = '';
122 } elseif ($token === ',') {
123 $statements[strtolower($alias)] = $groupRoot . $class;
124 $class = '';
125 $alias = '';
126 $explicitAlias = \false;
127 } elseif ($token === ';') {
128 $statements[strtolower($alias)] = $groupRoot . $class;
129 break;
130 } elseif ($token === '{') {
131 $groupRoot = $class;
132 $class = '';
133 } elseif ($token === '}') {
134 continue;
135 } else {
136 break;
137 }
138 }
139 return $statements;
140 }
141 /**
142 * Gets the namespace.
143 *
144 * @return string The found namespace.
145 */
146 private function parseNamespace()
147 {
148 $name = '';
149 while (($token = $this->next()) && ($token[0] === \T_STRING || $token[0] === \T_NS_SEPARATOR || \PHP_VERSION_ID >= 80000 && ($token[0] === \T_NAME_QUALIFIED || $token[0] === \T_NAME_FULLY_QUALIFIED))) {
150 $name .= $token[1];
151 }
152 return $name;
153 }
154 }
155