1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Patsura Dmitry https://github.com/ovr <[email protected]> |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace PHPSA; |
7
|
|
|
|
8
|
|
|
use PHPSA\Definition\ClassDefinition; |
9
|
|
|
use PHPSA\Definition\FunctionDefinition; |
10
|
|
|
use PHPSA\Definition\InterfaceDefinition; |
11
|
|
|
use PHPSA\Definition\RuntimeClassDefinition; |
12
|
|
|
use PHPSA\Definition\TraitDefinition; |
13
|
|
|
use PHPSA\Definition\RuntimeInterfaceDefinition; |
14
|
|
|
use ReflectionClass; |
15
|
|
|
|
16
|
|
|
class Compiler |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var ClassDefinition[] |
20
|
|
|
*/ |
21
|
|
|
protected $classes = []; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var TraitDefinition[] |
25
|
|
|
*/ |
26
|
|
|
protected $traits = array(); |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var FunctionDefinition[] |
30
|
|
|
*/ |
31
|
|
|
protected $functions = []; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var InterfaceDefinition[] |
35
|
|
|
*/ |
36
|
|
|
protected $interfaces = []; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @param ClassDefinition $class |
40
|
|
|
*/ |
41
|
25 |
|
public function addClass(ClassDefinition $class) |
42
|
|
|
{ |
43
|
25 |
|
$this->classes[implode('\\', [$class->getNamespace(), $class->getName()])] = $class; |
44
|
25 |
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @param TraitDefinition $class |
48
|
|
|
*/ |
49
|
|
|
public function addTrait(TraitDefinition $class) |
50
|
|
|
{ |
51
|
|
|
$this->traits[implode('\\', [$class->getNamespace(), $class->getName()])] = $class; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @param FunctionDefinition $function |
56
|
|
|
*/ |
57
|
1 |
|
public function addFunction(FunctionDefinition $function) |
58
|
|
|
{ |
59
|
1 |
|
$this->functions[] = $function; |
60
|
1 |
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @param InterfaceDefinition $interface |
64
|
|
|
*/ |
65
|
|
|
public function addInterface(InterfaceDefinition $interface) |
66
|
|
|
{ |
67
|
|
|
$this->interfaces[implode('\\', [$interface->getNamespace(), $interface->getName()])] = $interface; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @param Context $context |
72
|
|
|
*/ |
73
|
25 |
|
public function compile(Context $context) |
|
|
|
|
74
|
|
|
{ |
75
|
25 |
|
$context->scopePointer = null; |
76
|
|
|
|
77
|
25 |
|
foreach ($this->interfaces as $interface) { |
78
|
|
|
foreach ($interface->getExtendsInterface() as $extendsInterface) { |
79
|
|
|
if (isset($this->interfaces[$extendsInterface])) { |
80
|
|
|
$interface->addExtendsInterfaceDefinition($this->interfaces[$extendsInterface]); |
81
|
|
|
continue; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
if (class_exists($extendsInterface, true)) { |
85
|
|
|
$interface->addExtendsInterfaceDefinition( |
86
|
|
|
new RuntimeInterfaceDefinition(new ReflectionClass($extendsInterface)) |
87
|
|
|
); |
88
|
|
|
} |
89
|
|
|
} |
90
|
25 |
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @todo Implement class map... |
94
|
|
|
*/ |
95
|
25 |
|
foreach ($this->classes as $class) { |
96
|
25 |
|
$extends = $class->getExtendsClass(); |
97
|
25 |
|
if ($extends) { |
|
|
|
|
98
|
|
|
if (isset($this->classes[$extends])) { |
99
|
|
|
$class->setExtendsClassDefinition($this->classes[$extends]); |
100
|
|
|
} else { |
101
|
|
|
if (class_exists($extends, true)) { |
102
|
|
|
$class->setExtendsClassDefinition( |
103
|
|
|
new RuntimeClassDefinition( |
104
|
|
|
new ReflectionClass( |
105
|
|
|
$extends |
106
|
|
|
) |
107
|
|
|
) |
108
|
|
|
); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
25 |
|
foreach ($class->getInterfaces() as $interface) { |
114
|
|
|
if (!isset($this->interfaces[$interface])) { |
115
|
|
|
continue; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
$class->addInterfaceDefinition($this->interfaces[$interface]); |
119
|
25 |
|
} |
120
|
25 |
|
} |
121
|
|
|
|
122
|
25 |
|
foreach ($this->interfaces as $interface) { |
123
|
|
|
/** |
124
|
|
|
* @todo Configuration |
125
|
|
|
* |
126
|
|
|
* Ignore Interfaces compiling from vendor |
127
|
|
|
*/ |
128
|
|
|
$checkVendor = strpos($class->getFilepath(), './vendor'); |
|
|
|
|
129
|
|
|
if ($checkVendor !== false && $checkVendor < 3) { |
130
|
|
|
continue; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$interface->compile($context); |
134
|
25 |
|
} |
135
|
|
|
|
136
|
25 |
|
foreach ($this->functions as $function) { |
137
|
|
|
/** |
138
|
|
|
* @todo Configuration |
139
|
|
|
* |
140
|
|
|
* Ignore functions compiling from vendor |
141
|
|
|
*/ |
142
|
1 |
|
$checkVendor = strpos($function->getFilepath(), './vendor'); |
143
|
1 |
|
if ($checkVendor !== false && $checkVendor < 3) { |
144
|
|
|
continue; |
145
|
|
|
} |
146
|
|
|
|
147
|
1 |
|
$function->compile($context); |
148
|
25 |
|
} |
149
|
|
|
|
150
|
25 |
|
foreach ($this->classes as $class) { |
151
|
|
|
/** |
152
|
|
|
* @todo Configuration |
153
|
|
|
* |
154
|
|
|
* Ignore Classes compiling from vendor |
155
|
|
|
*/ |
156
|
25 |
|
$checkVendor = strpos($class->getFilepath(), './vendor'); |
157
|
25 |
|
if ($checkVendor !== false && $checkVendor < 3) { |
158
|
|
|
continue; |
159
|
|
|
} |
160
|
|
|
|
161
|
25 |
|
$class->compile($context); |
162
|
25 |
|
} |
163
|
25 |
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Try to find function with $namespace from pre-compiled function(s) |
167
|
|
|
* |
168
|
|
|
* @param string $name |
169
|
|
|
* @param string|null $namespace |
170
|
|
|
* @return bool|FunctionDefinition |
171
|
|
|
*/ |
172
|
10 |
|
public function getFunctionNS($name, $namespace = null) |
173
|
|
|
{ |
174
|
10 |
|
foreach ($this->functions as $function) { |
175
|
1 |
|
if ($function->getName() == $name && $function->getNamespace() == $namespace) { |
176
|
|
|
return $function; |
177
|
|
|
} |
178
|
10 |
|
} |
179
|
|
|
|
180
|
10 |
|
return false; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @param string $name |
185
|
|
|
* @return TraitDefinition|null |
186
|
|
|
*/ |
187
|
|
|
public function getTrait($name) |
188
|
|
|
{ |
189
|
|
|
if (isset($this->traits[$name])) { |
190
|
|
|
return $this->traits[$name]; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
return null; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Try to find function from pre-compiled function(s) |
198
|
|
|
* |
199
|
|
|
* @param string $name |
200
|
|
|
* @return bool|FunctionDefinition |
201
|
|
|
*/ |
202
|
1 |
|
public function getFunction($name) |
203
|
|
|
{ |
204
|
1 |
|
foreach ($this->functions as $function) { |
205
|
1 |
|
if ($function->getName() == $name) { |
206
|
|
|
return $function; |
207
|
|
|
} |
208
|
1 |
|
} |
209
|
|
|
|
210
|
1 |
|
return false; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.
You can also find more information in the “Code” section of your repository.