This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types=1); |
||
2 | |||
3 | namespace Igni\Utils\ReflectionApi; |
||
4 | |||
5 | use Igni\Utils\Exception\ReflectionApiException; |
||
6 | use Igni\Utils\ReflectionApi; |
||
7 | |||
8 | final class RuntimeClass implements CodeGenerator |
||
9 | { |
||
10 | use FinalTrait; |
||
11 | use AbstractTrait; |
||
12 | |||
13 | /** |
||
14 | * @var string |
||
15 | */ |
||
16 | private $class; |
||
17 | |||
18 | /** |
||
19 | * @var string |
||
20 | */ |
||
21 | private $className; |
||
22 | |||
23 | /** |
||
24 | * @var string[] |
||
25 | */ |
||
26 | private $namespace; |
||
27 | |||
28 | /** |
||
29 | * @var string |
||
30 | */ |
||
31 | private $extends; |
||
32 | |||
33 | /** |
||
34 | * @var string[] |
||
35 | */ |
||
36 | private $implements = []; |
||
37 | |||
38 | /** |
||
39 | * @var string[] |
||
40 | */ |
||
41 | private $uses = []; |
||
42 | |||
43 | /** |
||
44 | * @var bool |
||
45 | */ |
||
46 | private $isLoaded = false; |
||
47 | |||
48 | /** |
||
49 | * @var RuntimeMethod[] |
||
50 | */ |
||
51 | private $methods = []; |
||
52 | |||
53 | /** |
||
54 | * @var RuntimeProperty[] |
||
55 | */ |
||
56 | private $properties = []; |
||
57 | |||
58 | /** |
||
59 | * @var RuntimeConstant[] |
||
60 | */ |
||
61 | private $constant = []; |
||
62 | |||
63 | /** |
||
64 | * @var string[] |
||
65 | */ |
||
66 | private static $registeredClasses = []; |
||
67 | |||
68 | 16 | public function __construct(string $class, string ...$implements) |
|
69 | { |
||
70 | 16 | if (isset(self::$registeredClasses[$class]) || class_exists($class) || interface_exists($class)) { |
|
71 | 1 | throw ReflectionApiException::forAlreadyDefinedClass($class); |
|
72 | } |
||
73 | |||
74 | 15 | $this->class = $class; |
|
75 | 15 | $classParts = explode('\\', $class); |
|
76 | 15 | $this->className = array_pop($classParts); |
|
77 | 15 | $this->namespace = implode('\\', $classParts); |
|
0 ignored issues
–
show
|
|||
78 | |||
79 | 15 | $this->implements(...$implements); |
|
80 | 15 | } |
|
81 | |||
82 | 2 | public function getNamespace(): string |
|
83 | { |
||
84 | 2 | return $this->namespace; |
|
85 | } |
||
86 | |||
87 | 1 | public function getClass(): string |
|
88 | { |
||
89 | 1 | return $this->class; |
|
90 | } |
||
91 | |||
92 | 1 | public function getClassName(): string |
|
93 | { |
||
94 | 1 | return $this->className; |
|
95 | } |
||
96 | |||
97 | 15 | public function implements(string ...$interfaces): self |
|
98 | { |
||
99 | 15 | foreach ($interfaces as &$interface) { |
|
100 | 2 | if (!interface_exists($interface)) { |
|
101 | throw ReflectionApiException::forNonExistentInterface($interface); |
||
102 | } |
||
103 | 2 | $interface = '\\' . $interface; |
|
104 | } |
||
105 | 15 | $this->implements = $interfaces; |
|
106 | |||
107 | 15 | return $this; |
|
108 | } |
||
109 | |||
110 | 1 | public function extends(string $class): self |
|
111 | { |
||
112 | 1 | if (!class_exists($class)) { |
|
113 | throw ReflectionApiException::forNonExistentClass($class); |
||
114 | } |
||
115 | 1 | $this->extends = '\\' . $class; |
|
116 | |||
117 | 1 | return $this; |
|
118 | } |
||
119 | |||
120 | public function use(string ...$traits): self |
||
121 | { |
||
122 | foreach ($traits as &$trait) { |
||
123 | if (!trait_exists($trait)) { |
||
124 | throw ReflectionApiException::forNonExistentTrait($trait); |
||
125 | } |
||
126 | $trait = '\\' . $trait; |
||
127 | } |
||
128 | $this->uses = $traits; |
||
129 | |||
130 | return $this; |
||
131 | } |
||
132 | |||
133 | public function isUsing(string $name): bool |
||
134 | { |
||
135 | return in_array('\\' . $name, $this->uses); |
||
136 | } |
||
137 | |||
138 | 1 | public function isExtending(string $name): bool |
|
139 | { |
||
140 | 1 | return ('\\' . $name) === $this->extends; |
|
141 | } |
||
142 | |||
143 | 1 | public function implementsInterface(string $interface): bool |
|
144 | { |
||
145 | 1 | return in_array('\\' . $interface, $this->implements); |
|
146 | } |
||
147 | |||
148 | 2 | public function addMethod(RuntimeMethod $method): self |
|
149 | { |
||
150 | 2 | $this->methods[$method->getName()] = $method; |
|
151 | |||
152 | 2 | return $this; |
|
153 | } |
||
154 | |||
155 | 1 | public function hasMethod(string $name): bool |
|
156 | { |
||
157 | 1 | return isset($this->methods[$name]); |
|
158 | } |
||
159 | |||
160 | 1 | public function addProperty(RuntimeProperty $property): self |
|
161 | { |
||
162 | 1 | $this->properties[$property->getName()] = $property; |
|
163 | |||
164 | 1 | return $this; |
|
165 | } |
||
166 | |||
167 | 1 | public function addConstant(RuntimeConstant $constant): self |
|
168 | { |
||
169 | 1 | $this->constant[$constant->getName()] = $constant; |
|
170 | |||
171 | 1 | return $this; |
|
172 | } |
||
173 | |||
174 | 1 | public function hasConstant(string $name): bool |
|
175 | { |
||
176 | 1 | return isset($this->constant[$name]); |
|
177 | } |
||
178 | |||
179 | 1 | public function hasProperty(string $name): bool |
|
180 | { |
||
181 | 1 | return isset($this->properties[$name]); |
|
182 | } |
||
183 | |||
184 | 10 | public function generateCode(): string |
|
185 | { |
||
186 | 10 | $code = ''; |
|
187 | 10 | if ($this->namespace) { |
|
0 ignored issues
–
show
The expression
$this->namespace of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
188 | 1 | $code .= "namespace {$this->namespace} {\n"; |
|
189 | } |
||
190 | |||
191 | 10 | if ($this->final) { |
|
192 | 1 | $code .= 'final '; |
|
193 | } |
||
194 | |||
195 | 10 | if ($this->abstract) { |
|
196 | 1 | $code .= 'abstract '; |
|
197 | } |
||
198 | |||
199 | 10 | $code .= "class {$this->className}"; |
|
200 | |||
201 | 10 | if ($this->extends) { |
|
202 | 1 | $code .= " extends {$this->extends}"; |
|
203 | } |
||
204 | |||
205 | 10 | if ($this->implements) { |
|
0 ignored issues
–
show
The expression
$this->implements of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
206 | 2 | $code .= ' implements ' . implode(',', $this->implements); |
|
207 | } |
||
208 | |||
209 | 10 | $code .= "\n{\n"; |
|
210 | |||
211 | 10 | foreach ($this->constant as $constant) { |
|
212 | 1 | $code .= "\t{$constant->generateCode()}\n"; |
|
213 | } |
||
214 | |||
215 | 10 | foreach ($this->properties as $property) { |
|
216 | 1 | $code .= "\t{$property->generateCode()}\n"; |
|
217 | } |
||
218 | |||
219 | 10 | foreach ($this->methods as $method) { |
|
220 | 2 | $methodBody = explode("\n", $method->generateCode()); |
|
221 | 2 | foreach ($methodBody as $methodLine) { |
|
222 | 2 | $code .= "\t" . $methodLine . PHP_EOL; |
|
223 | } |
||
224 | } |
||
225 | |||
226 | 10 | $code .= "}\n"; |
|
227 | |||
228 | 10 | if ($this->namespace) { |
|
0 ignored issues
–
show
The expression
$this->namespace of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
229 | 1 | $code .= "\n}\n"; |
|
230 | } |
||
231 | |||
232 | 10 | return $code; |
|
233 | } |
||
234 | |||
235 | 1 | public function createInstance() |
|
236 | { |
||
237 | 1 | $this->load(); |
|
238 | |||
239 | 1 | return ReflectionApi::createInstance($this->class); |
|
240 | } |
||
241 | |||
242 | 2 | public function register(): bool |
|
243 | { |
||
244 | 2 | if (isset(self::$registeredClasses[$this->class])) { |
|
245 | return false; |
||
246 | } |
||
247 | |||
248 | 2 | self::$registeredClasses[$this->class] = $this->class; |
|
249 | |||
250 | 2 | return true; |
|
251 | } |
||
252 | |||
253 | 2 | public function load(): bool |
|
254 | { |
||
255 | 2 | if (!$this->register()) { |
|
256 | throw ReflectionApiException::forAlreadyDefinedClass($this->class); |
||
257 | } |
||
258 | |||
259 | 2 | if ($this->isLoaded) { |
|
260 | return $this->isLoaded; |
||
261 | } |
||
262 | |||
263 | try { |
||
264 | 2 | $fileName = tempnam(sys_get_temp_dir(), 'igni-reflection-api'); |
|
265 | 2 | $file = fopen($fileName,'w'); |
|
266 | 2 | fwrite($file, '<?php ' . $this); |
|
267 | 2 | fclose($file); |
|
268 | 2 | $this->isLoaded = true; |
|
269 | |||
270 | 2 | require_once $fileName; |
|
271 | |||
272 | } catch (\Throwable $exception) { |
||
273 | return false; |
||
274 | } |
||
275 | |||
276 | 2 | return true; |
|
277 | } |
||
278 | |||
279 | 2 | public function __toString(): string |
|
280 | { |
||
281 | 2 | return $this->generateCode(); |
|
282 | } |
||
283 | } |
||
284 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..