PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.9
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.9
4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 All 200 releases
betterdocs / includes / Dependencies / SuperClosure / Analyzer / TokenAnalyzer.php

TokenAnalyzer.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 3.8.9, at includes/Dependencies/SuperClosure/Analyzer/TokenAnalyzer.php

119 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace WPDeveloper\BetterDocs\Dependencies\SuperClosure\Analyzer;
2
3 use WPDeveloper\BetterDocs\Dependencies\SuperClosure\Exception\ClosureAnalysisException;
4
5 /**
6 * This is the token based analyzer.
7 *
8 * We're using Uses reflection and tokenization to analyze a closure and
9 * determine its code and context. This is much faster than the AST based
10 * implementation.
11 */
12 class TokenAnalyzer extends ClosureAnalyzer
13 {
14 public function determineCode(array &$data)
15 {
16 $this->determineTokens($data);
17 $data['code'] = implode('', $data['tokens']);
18 $data['hasThis'] = (strpos($data['code'], '$this') !== false);
19 }
20
21 private function determineTokens(array &$data)
22 {
23 $potential = $this->determinePotentialTokens($data['reflection']);
24 $braceLevel = $index = $step = $insideUse = 0;
25 $data['tokens'] = $data['context'] = [];
26
27 foreach ($potential as $token) {
28 $token = new Token($token);
29 switch ($step) {
30 // Handle tokens before the function declaration.
31 case 0:
32 if ($token->is(T_FUNCTION)) {
33 $data['tokens'][] = $token;
34 $step++;
35 }
36 break;
37 // Handle tokens inside the function signature.
38 case 1:
39 $data['tokens'][] = $token;
40 if ($insideUse) {
41 if ($token->is(T_VARIABLE)) {
42 $varName = trim($token, '$ ');
43 $data['context'][$varName] = null;
44 } elseif ($token->is('&')) {
45 $data['hasRefs'] = true;
46 }
47 } elseif ($token->is(T_USE)) {
48 $insideUse++;
49 }
50 if ($token->is('{')) {
51 $step++;
52 $braceLevel++;
53 }
54 break;
55 // Handle tokens inside the function body.
56 case 2:
57 $data['tokens'][] = $token;
58 if ($token->is('{')) {
59 $braceLevel++;
60 } elseif ($token->is('}')) {
61 $braceLevel--;
62 if ($braceLevel === 0) {
63 $step++;
64 }
65 }
66 break;
67 // Handle tokens after the function declaration.
68 case 3:
69 if ($token->is(T_FUNCTION)) {
70 throw new ClosureAnalysisException('Multiple closures '
71 . 'were declared on the same line of code. Could not '
72 . 'determine which closure was the intended target.'
73 );
74 }
75 break;
76 }
77 }
78 }
79
80 private function determinePotentialTokens(\ReflectionFunction $reflection)
81 {
82 // Load the file containing the code for the function.
83 $fileName = $reflection->getFileName();
84 if (!is_readable($fileName)) {
85 throw new ClosureAnalysisException(
86 "Cannot read the file containing the closure: \"{$fileName}\"."
87 );
88 }
89
90 $code = '';
91 $file = new \SplFileObject($fileName);
92 $file->seek($reflection->getStartLine() - 1);
93 while ($file->key() < $reflection->getEndLine()) {
94 $code .= $file->current();
95 $file->next();
96 }
97
98 $code = trim($code);
99 if (strpos($code, '<?php') !== 0) {
100 $code = "<?php\n" . $code;
101 }
102
103 return token_get_all($code);
104 }
105
106 protected function determineContext(array &$data)
107 {
108 // Get the values of the variables that are closed upon in "use".
109 $values = $data['reflection']->getStaticVariables();
110
111 // Construct the context by combining the variable names and values.
112 foreach ($data['context'] as $name => &$value) {
113 if (isset($values[$name])) {
114 $value = $values[$name];
115 }
116 }
117 }
118 }
119