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 / Visitor / ClosureLocatorVisitor.php

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

121 lines 4.6 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\Visitor;
2
3 use WPDeveloper\BetterDocs\Dependencies\SuperClosure\Exception\ClosureAnalysisException;
4 use WPDeveloper\BetterDocs\Dependencies\PhpParser\Node\Stmt\Namespace_ as NamespaceNode;
5 use WPDeveloper\BetterDocs\Dependencies\PhpParser\Node\Stmt\Trait_ as TraitNode;
6 use WPDeveloper\BetterDocs\Dependencies\PhpParser\Node\Stmt\Class_ as ClassNode;
7 use WPDeveloper\BetterDocs\Dependencies\PhpParser\Node\Expr\Closure as ClosureNode;
8 use WPDeveloper\BetterDocs\Dependencies\PhpParser\Node as AstNode;
9 use WPDeveloper\BetterDocs\Dependencies\PhpParser\NodeVisitorAbstract as NodeVisitor;
10
11 /**
12 * This is a visitor that extends the nikic/php-parser library and looks for a
13 * closure node and its location.
14 *
15 * @internal
16 */
17 final class ClosureLocatorVisitor extends NodeVisitor
18 {
19 /**
20 * @var \ReflectionFunction
21 */
22 private $reflection;
23
24 /**
25 * @var ClosureNode
26 */
27 public $closureNode;
28
29 /**
30 * @var array
31 */
32 public $location;
33
34 /**
35 * @param \ReflectionFunction $reflection
36 */
37 public function __construct($reflection)
38 {
39 $this->reflection = $reflection;
40 $this->location = [
41 'class' => null,
42 'directory' => dirname($this->reflection->getFileName()),
43 'file' => $this->reflection->getFileName(),
44 'function' => $this->reflection->getName(),
45 'line' => $this->reflection->getStartLine(),
46 'method' => null,
47 'namespace' => null,
48 'trait' => null,
49 ];
50 }
51
52 public function enterNode(AstNode $node)
53 {
54 // Determine information about the closure's location
55 if (!$this->closureNode) {
56 if ($node instanceof NamespaceNode) {
57 $namespace = $node->name !== null
58 ? $node->name->toString()
59 : null;
60 $this->location['namespace'] = $namespace;
61 }
62 if ($node instanceof TraitNode) {
63 $this->location['trait'] = (string) $node->name;
64 $this->location['class'] = null;
65 } elseif ($node instanceof ClassNode) {
66 $this->location['class'] = (string) $node->name;
67 $this->location['trait'] = null;
68 }
69 }
70
71 // Locate the node of the closure
72 if ($node instanceof ClosureNode) {
73 if ($node->getAttribute('startLine') == $this->location['line']) {
74 if ($this->closureNode) {
75 $line = $this->location['file'] . ':' . $node->getAttribute('startLine');
76 throw new ClosureAnalysisException("Two closures were "
77 . "declared on the same line ({$line}) of code. Cannot "
78 . "determine which closure was the intended target.");
79 } else {
80 $this->closureNode = $node;
81 }
82 }
83 }
84 }
85
86 public function leaveNode(AstNode $node)
87 {
88 // Determine information about the closure's location
89 if (!$this->closureNode) {
90 if ($node instanceof NamespaceNode) {
91 $this->location['namespace'] = null;
92 }
93 if ($node instanceof TraitNode) {
94 $this->location['trait'] = null;
95 } elseif ($node instanceof ClassNode) {
96 $this->location['class'] = null;
97 }
98 }
99 }
100
101 public function afterTraverse(array $nodes)
102 {
103 if ($this->location['class']) {
104 $this->location['class'] = $this->location['namespace'] . '\\' . $this->location['class'];
105 $this->location['method'] = "{$this->location['class']}::{$this->location['function']}";
106 } elseif ($this->location['trait']) {
107 $this->location['trait'] = $this->location['namespace'] . '\\' . $this->location['trait'];
108 $this->location['method'] = "{$this->location['trait']}::{$this->location['function']}";
109
110 // If the closure was declared in a trait, then we will do a best
111 // effort guess on the name of the class that used the trait. It's
112 // actually impossible at this point to know for sure what it is.
113 if ($closureScope = $this->reflection->getClosureScopeClass()) {
114 $this->location['class'] = $closureScope ? $closureScope->getName() : null;
115 } elseif ($closureThis = $this->reflection->getClosureThis()) {
116 $this->location['class'] = get_class($closureThis);
117 }
118 }
119 }
120 }
121