Complex classes like Expression often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Expression, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class Expression |
||
|
|||
21 | { |
||
22 | /** |
||
23 | * @var Context |
||
24 | */ |
||
25 | protected $context; |
||
26 | |||
27 | /** |
||
28 | * @var EventManager |
||
29 | */ |
||
30 | protected $eventManager; |
||
31 | |||
32 | /** |
||
33 | * @param Context $context |
||
34 | */ |
||
35 | 402 | public function __construct(Context $context, EventManager $eventManager) |
|
36 | { |
||
37 | 402 | $this->context = $context; |
|
38 | 402 | $this->eventManager = $eventManager; |
|
39 | 402 | } |
|
40 | |||
41 | /** |
||
42 | * @param $expr |
||
43 | * @return ExpressionCompilerInterface|AbstractExpressionCompiler |
||
44 | */ |
||
45 | 389 | protected function factory($expr) |
|
46 | { |
||
47 | 389 | switch (get_class($expr)) { |
|
48 | /** |
||
49 | * Call(s) |
||
50 | */ |
||
51 | 389 | case Node\Expr\MethodCall::class: |
|
52 | return new Expression\MethodCall(); |
||
53 | 389 | case Node\Expr\FuncCall::class: |
|
54 | 10 | return new Expression\FunctionCall(); |
|
55 | 381 | case Node\Expr\StaticCall::class: |
|
56 | return new Expression\StaticCall(); |
||
57 | /** |
||
58 | * Operators |
||
59 | */ |
||
60 | 381 | case Node\Expr\New_::class: |
|
61 | 1 | return new Expression\Operators\NewOp(); |
|
62 | 380 | case Node\Expr\Instanceof_::class: |
|
63 | return new Expression\Operators\InstanceOfOp(); |
||
64 | /** |
||
65 | * AssignOp |
||
66 | */ |
||
67 | 380 | case Node\Expr\AssignOp\Pow::class: |
|
68 | return new Expression\AssignOp\Pow(); |
||
69 | 380 | case Node\Expr\AssignOp\Plus::class: |
|
70 | return new Expression\AssignOp\Plus(); |
||
71 | 380 | case Node\Expr\AssignOp\Minus::class: |
|
72 | return new Expression\AssignOp\Minus(); |
||
73 | 380 | case Node\Expr\AssignOp\Mod::class: |
|
74 | return new Expression\AssignOp\Mod(); |
||
75 | 380 | case Node\Expr\AssignOp\BitwiseOr::class: |
|
76 | return new Expression\AssignOp\BitwiseOr(); |
||
77 | 380 | case Node\Expr\AssignOp\BitwiseAnd::class: |
|
78 | return new Expression\AssignOp\BitwiseAnd(); |
||
79 | /** |
||
80 | * BinaryOp |
||
81 | */ |
||
82 | 380 | case Node\Expr\BinaryOp\Identical::class: |
|
83 | 28 | return new Expression\BinaryOp\Identical(); |
|
84 | 352 | case Node\Expr\BinaryOp\Concat::class: |
|
85 | 1 | return new Expression\Operators\Concat(); |
|
86 | 351 | case Node\Expr\BinaryOp\NotIdentical::class: |
|
87 | 14 | return new Expression\BinaryOp\NotIdentical(); |
|
88 | 337 | case Node\Expr\BinaryOp\Equal::class: |
|
89 | 34 | return new Expression\BinaryOp\Equal(); |
|
90 | 303 | case Node\Expr\BinaryOp\NotEqual::class: |
|
91 | 17 | return new Expression\BinaryOp\NotEqual(); |
|
92 | /** |
||
93 | * @link http://php.net/manual/en/language.operators.increment.php |
||
94 | */ |
||
95 | 286 | case Node\Expr\PostInc::class: |
|
96 | 4 | return new Expression\Operators\PostInc(); |
|
97 | 282 | case Node\Expr\PostDec::class: |
|
98 | 4 | return new Expression\Operators\PostDec(); |
|
99 | /** |
||
100 | * Arithmetical |
||
101 | */ |
||
102 | 278 | case Node\Expr\BinaryOp\Div::class: |
|
103 | 37 | return new Expression\Operators\Arithmetical\Div(); |
|
104 | 241 | case Node\Expr\BinaryOp\Plus::class: |
|
105 | 45 | return new Expression\Operators\Arithmetical\Plus(); |
|
106 | 196 | case Node\Expr\BinaryOp\Minus::class: |
|
107 | 18 | return new Expression\Operators\Arithmetical\Minus(); |
|
108 | 178 | case Node\Expr\BinaryOp\Mul::class: |
|
109 | 35 | return new Expression\Operators\Arithmetical\Mul(); |
|
110 | 143 | case Node\Expr\BinaryOp\Mod::class: |
|
111 | 35 | return new Expression\Operators\Arithmetical\Mod(); |
|
112 | /** |
||
113 | * Bitwise |
||
114 | * @link http://php.net/manual/ru/language.operators.bitwise.php |
||
115 | */ |
||
116 | 108 | case Node\Expr\BinaryOp\BitwiseOr::class: |
|
117 | return new Expression\Operators\Bitwise\BitwiseOr(); |
||
118 | 108 | case Node\Expr\BinaryOp\BitwiseXor::class: |
|
119 | return new Expression\Operators\Bitwise\BitwiseXor(); |
||
120 | 108 | case Node\Expr\BinaryOp\BitwiseAnd::class: |
|
121 | return new Expression\Operators\Bitwise\BitwiseAnd(); |
||
122 | 108 | case Node\Expr\BinaryOp\ShiftRight::class: |
|
123 | return new Expression\Operators\Bitwise\ShiftRight(); |
||
124 | 108 | case Node\Expr\BinaryOp\ShiftLeft::class: |
|
125 | return new Expression\Operators\Bitwise\ShiftLeft(); |
||
126 | 108 | case Node\Expr\BitwiseNot::class: |
|
127 | return new Expression\Operators\Bitwise\BitwiseNot(); |
||
128 | /** |
||
129 | * Logical |
||
130 | */ |
||
131 | 108 | case Node\Expr\BinaryOp\BooleanOr::class: |
|
132 | 17 | return new Expression\Operators\Logical\BooleanOr(); |
|
133 | 91 | case Node\Expr\BinaryOp\BooleanAnd::class: |
|
134 | 15 | return new Expression\Operators\Logical\BooleanAnd(); |
|
135 | 76 | case Node\Expr\BooleanNot::class: |
|
136 | 9 | return new Expression\Operators\Logical\BooleanNot(); |
|
137 | /** |
||
138 | * Comparison |
||
139 | */ |
||
140 | 67 | case Node\Expr\BinaryOp\Greater::class: |
|
141 | 12 | return new Expression\Operators\Comparison\Greater(); |
|
142 | 55 | case Node\Expr\BinaryOp\GreaterOrEqual::class: |
|
143 | 12 | return new Expression\Operators\Comparison\GreaterOrEqual(); |
|
144 | 43 | case Node\Expr\BinaryOp\Smaller::class: |
|
145 | 12 | return new Expression\Operators\Comparison\Smaller(); |
|
146 | 31 | case Node\Expr\BinaryOp\SmallerOrEqual::class: |
|
147 | 12 | return new Expression\Operators\Comparison\SmallerOrEqual(); |
|
148 | /** |
||
149 | * Other |
||
150 | */ |
||
151 | 19 | case Node\Expr\Closure::class: |
|
152 | return new Expression\Closure(); |
||
153 | 19 | case Node\Expr\UnaryMinus::class: |
|
154 | 9 | return new Expression\Operators\UnaryMinus(); |
|
155 | 10 | case Node\Expr\UnaryPlus::class: |
|
156 | 9 | return new Expression\Operators\UnaryPlus(); |
|
157 | 1 | } |
|
158 | |||
159 | 1 | return false; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * @param object|string $expr |
||
164 | * @return CompiledExpression |
||
165 | */ |
||
166 | 402 | public function compile($expr) |
|
167 | { |
||
168 | 402 | if (is_string($expr)) { |
|
169 | return new CompiledExpression(CompiledExpression::STRING, $expr); |
||
170 | } |
||
171 | |||
172 | 402 | if (is_null($expr)) { |
|
173 | 1 | return new CompiledExpression(CompiledExpression::NULL); |
|
174 | } |
||
175 | |||
176 | 402 | if (!is_object($expr)) { |
|
177 | throw new InvalidArgumentException('$expr must be string/object/null'); |
||
178 | } |
||
179 | |||
180 | 402 | $this->eventManager->fire( |
|
181 | 402 | ExpressionBeforeCompile::EVENT_NAME, |
|
182 | 402 | new ExpressionBeforeCompile( |
|
183 | 402 | $expr, |
|
184 | 402 | $this->context |
|
185 | 402 | ) |
|
186 | 402 | ); |
|
187 | |||
188 | 402 | $className = get_class($expr); |
|
189 | 1 | switch ($className) { |
|
190 | 402 | case Node\Arg::class: |
|
191 | /** |
||
192 | * @todo Better compile |
||
193 | */ |
||
194 | 2 | return $this->compile($expr->value); |
|
195 | 402 | case Node\Expr\PropertyFetch::class: |
|
196 | return $this->passPropertyFetch($expr); |
||
197 | 402 | case Node\Stmt\Property::class: |
|
198 | return $this->passProperty($expr); |
||
199 | 402 | case Node\Expr\ClassConstFetch::class: |
|
200 | return $this->passConstFetch($expr); |
||
201 | 402 | case Node\Expr\Assign::class: |
|
202 | 8 | return $this->passSymbol($expr); |
|
203 | 402 | case Node\Expr\AssignRef::class: |
|
204 | 1 | return $this->passSymbolByRef($expr); |
|
205 | 402 | case Node\Expr\Variable::class: |
|
206 | 4 | return $this->passExprVariable($expr); |
|
207 | /** |
||
208 | * Cast operators |
||
209 | */ |
||
210 | 402 | case Node\Expr\Cast\Bool_::class: |
|
211 | return $this->passCastBoolean($expr); |
||
212 | 402 | case Node\Expr\Cast\Int_::class: |
|
213 | return $this->passCastInt($expr); |
||
214 | 402 | case Node\Expr\Cast\Double::class: |
|
215 | return $this->passCastFloat($expr); |
||
216 | 402 | case Node\Expr\Cast\String_::class: |
|
217 | return $this->passCastString($expr); |
||
218 | 402 | case Node\Expr\Cast\Unset_::class: |
|
219 | return $this->passCastUnset($expr); |
||
220 | /** |
||
221 | * Expressions |
||
222 | */ |
||
223 | 402 | case Node\Expr\Array_::class: |
|
224 | 20 | return $this->getArray($expr); |
|
225 | 401 | case Node\Expr\ConstFetch::class: |
|
226 | 4 | return $this->constFetch($expr); |
|
227 | 401 | case Node\Name::class: |
|
228 | 10 | return $this->getNodeName($expr); |
|
229 | 401 | case Node\Name\FullyQualified::class: |
|
230 | return $this->getFullyQualifiedNodeName($expr); |
||
231 | /** |
||
232 | * Simple Scalar(s) |
||
233 | */ |
||
234 | 401 | case \PHPSA\Node\Scalar\Nil::class: |
|
235 | 12 | return new CompiledExpression(CompiledExpression::NULL); |
|
236 | 400 | case Node\Scalar\LNumber::class: |
|
237 | 276 | return new CompiledExpression(CompiledExpression::INTEGER, $expr->value); |
|
238 | 395 | case Node\Scalar\DNumber::class: |
|
239 | 134 | return new CompiledExpression(CompiledExpression::DOUBLE, $expr->value); |
|
240 | 394 | case Node\Scalar\String_::class: |
|
241 | 20 | return new CompiledExpression(CompiledExpression::STRING, $expr->value); |
|
242 | 391 | case \PHPSA\Node\Scalar\Boolean::class: |
|
243 | 72 | return new CompiledExpression(CompiledExpression::BOOLEAN, $expr->value); |
|
244 | 389 | case \PHPSA\Node\Scalar\Fake::class: |
|
245 | 29 | return new CompiledExpression($expr->type, $expr->value); |
|
246 | } |
||
247 | |||
248 | 389 | $expressionCompiler = $this->factory($expr); |
|
249 | 389 | if (!$expressionCompiler) { |
|
250 | 1 | $this->context->debug("Expression compiler is not implemented for {$className}"); |
|
251 | 1 | return new CompiledExpression(CompiledExpression::UNIMPLEMENTED); |
|
252 | } |
||
253 | |||
254 | 389 | $result = $expressionCompiler->pass($expr, $this->context); |
|
255 | 389 | if (!$result instanceof CompiledExpression) { |
|
256 | throw new RuntimeException('Please return CompiledExpression from ' . get_class($expressionCompiler)); |
||
257 | } |
||
258 | |||
259 | 389 | return $result; |
|
260 | } |
||
261 | |||
262 | /** |
||
263 | * @todo Implement |
||
264 | * |
||
265 | * @param Node\Stmt\Property $st |
||
266 | * @return CompiledExpression |
||
267 | */ |
||
268 | public function passProperty(Node\Stmt\Property $st) |
||
269 | { |
||
270 | $docBlock = $st->getDocComment(); |
||
271 | if (!$docBlock) { |
||
272 | $this->context->notice( |
||
273 | 'missing-docblock', |
||
274 | sprintf('Missing docblock for $%s property', $st->props[0]->name), |
||
275 | $st |
||
276 | ); |
||
277 | |||
278 | return new CompiledExpression(); |
||
279 | } |
||
280 | |||
281 | $phpdoc = new \phpDocumentor\Reflection\DocBlock($docBlock->getText()); |
||
282 | |||
283 | $varTags = $phpdoc->getTagsByName('var'); |
||
284 | if ($varTags) { |
||
285 | /** @var \phpDocumentor\Reflection\DocBlock\Tag\VarTag $varTag */ |
||
286 | $varTag = current($varTags); |
||
287 | |||
288 | $typeResolver = new \phpDocumentor\Reflection\TypeResolver(); |
||
289 | |||
290 | try { |
||
291 | $type = $typeResolver->resolve($varTag->getType()); |
||
292 | } catch (\InvalidArgumentException $e) { |
||
293 | return new CompiledExpression(); |
||
294 | } |
||
295 | |||
296 | if ($type) { |
||
297 | switch (get_class($type)) { |
||
298 | case \phpDocumentor\Reflection\Types\Object_::class: |
||
299 | return new CompiledExpression( |
||
300 | CompiledExpression::OBJECT |
||
301 | ); |
||
302 | case \phpDocumentor\Reflection\Types\Integer::class: |
||
303 | return new CompiledExpression( |
||
304 | CompiledExpression::INTEGER |
||
305 | ); |
||
306 | case \phpDocumentor\Reflection\Types\String_::class: |
||
307 | return new CompiledExpression( |
||
308 | CompiledExpression::STRING |
||
309 | ); |
||
310 | case \phpDocumentor\Reflection\Types\Float_::class: |
||
311 | return new CompiledExpression( |
||
312 | CompiledExpression::DOUBLE |
||
313 | ); |
||
314 | case \phpDocumentor\Reflection\Types\Null_::class: |
||
315 | return new CompiledExpression( |
||
316 | CompiledExpression::NULL |
||
317 | ); |
||
318 | case \phpDocumentor\Reflection\Types\Boolean::class: |
||
319 | return new CompiledExpression( |
||
320 | CompiledExpression::BOOLEAN |
||
321 | ); |
||
322 | } |
||
323 | } |
||
324 | } |
||
325 | |||
326 | return new CompiledExpression(); |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * @param Node\Expr\Variable $expr |
||
331 | * @return CompiledExpression |
||
332 | */ |
||
333 | 1 | public function declareVariable(Node\Expr\Variable $expr) |
|
334 | { |
||
335 | 1 | $variable = $this->context->getSymbol($expr->name); |
|
336 | 1 | if (!$variable) { |
|
337 | 1 | $variable = new Variable($expr->name, null, CompiledExpression::UNKNOWN, $this->context->getCurrentBranch()); |
|
338 | 1 | $this->context->addVariable($variable); |
|
339 | 1 | } |
|
340 | |||
341 | 1 | return new CompiledExpression($variable->getType(), $variable->getValue(), $variable); |
|
342 | } |
||
343 | |||
344 | /** |
||
345 | * @param Node\Name\FullyQualified $expr |
||
346 | * @return CompiledExpression |
||
347 | */ |
||
348 | public function getFullyQualifiedNodeName(Node\Name\FullyQualified $expr) |
||
349 | { |
||
350 | $this->context->debug('Unimplemented FullyQualified', $expr); |
||
351 | |||
352 | return new CompiledExpression; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * @param Node\Name $expr |
||
357 | * @return CompiledExpression |
||
358 | */ |
||
359 | 10 | public function getNodeName(Node\Name $expr) |
|
360 | { |
||
361 | 10 | $nodeString = $expr->toString(); |
|
362 | 10 | if ($nodeString === 'null') { |
|
363 | return new CompiledExpression(CompiledExpression::NULL); |
||
364 | } |
||
365 | |||
366 | 10 | if (in_array($nodeString, ['parent'], true)) { |
|
367 | /** @var ClassDefinition $scope */ |
||
368 | $scope = $this->context->scope; |
||
369 | assert($scope instanceof ClassDefinition); |
||
370 | |||
371 | if ($scope->getExtendsClass()) { |
||
372 | $definition = $scope->getExtendsClassDefinition(); |
||
373 | if ($definition) { |
||
374 | return new CompiledExpression(CompiledExpression::OBJECT, $definition); |
||
375 | } |
||
376 | } else { |
||
377 | $this->context->notice( |
||
378 | 'no-parent', |
||
379 | 'Cannot access parent:: when current class scope has no parent', |
||
380 | $expr |
||
381 | ); |
||
382 | } |
||
383 | } |
||
384 | |||
385 | 10 | if (in_array($nodeString, ['self', 'static'], true)) { |
|
386 | return CompiledExpression::fromZvalValue($this->context->scope); |
||
387 | } |
||
388 | |||
389 | 10 | if (defined($nodeString)) { |
|
390 | 1 | return CompiledExpression::fromZvalValue(constant($expr)); |
|
391 | } |
||
392 | |||
393 | 10 | return new CompiledExpression(CompiledExpression::STRING, $expr->toString()); |
|
394 | } |
||
395 | |||
396 | /** |
||
397 | * (bool) {$expr} |
||
398 | * |
||
399 | * @param Node\Expr\Cast\Bool_ $expr |
||
400 | * @return CompiledExpression |
||
401 | */ |
||
402 | protected function passCastBoolean(Node\Expr\Cast\Bool_ $expr) |
||
403 | { |
||
404 | $compiledExpression = $this->compile($expr->expr); |
||
405 | |||
406 | switch ($compiledExpression->getType()) { |
||
407 | case CompiledExpression::BOOLEAN: |
||
408 | $this->context->notice('stupid-cast', "You are trying to cast 'boolean' to 'boolean'", $expr); |
||
409 | return $compiledExpression; |
||
410 | case CompiledExpression::DOUBLE: |
||
411 | case CompiledExpression::INTEGER: |
||
412 | case CompiledExpression::NUMBER: |
||
413 | case CompiledExpression::STRING: |
||
414 | return new CompiledExpression(CompiledExpression::BOOLEAN, (bool) $compiledExpression->getValue()); |
||
415 | } |
||
416 | |||
417 | return new CompiledExpression(); |
||
418 | } |
||
419 | |||
420 | /** |
||
421 | * (int) {$expr} |
||
422 | * |
||
423 | * @param Node\Expr\Cast\Int_ $expr |
||
424 | * @return CompiledExpression |
||
425 | */ |
||
426 | protected function passCastInt(Node\Expr\Cast\Int_ $expr) |
||
427 | { |
||
428 | $compiledExpression = $this->compile($expr->expr); |
||
429 | |||
430 | switch ($compiledExpression->getType()) { |
||
431 | case CompiledExpression::INTEGER: |
||
432 | $this->context->notice('stupid-cast', "You are trying to cast 'int' to 'int'", $expr); |
||
433 | return $compiledExpression; |
||
434 | case CompiledExpression::BOOLEAN: |
||
435 | case CompiledExpression::DOUBLE: |
||
436 | case CompiledExpression::NUMBER: |
||
437 | case CompiledExpression::STRING: |
||
438 | return new CompiledExpression(CompiledExpression::INTEGER, (int) $compiledExpression->getValue()); |
||
439 | } |
||
440 | |||
441 | return new CompiledExpression(); |
||
442 | } |
||
443 | |||
444 | /** |
||
445 | * (float) {$expr} |
||
446 | * |
||
447 | * @param Node\Expr\Cast\Double $expr |
||
448 | * @return CompiledExpression |
||
449 | */ |
||
450 | protected function passCastFloat(Node\Expr\Cast\Double $expr) |
||
451 | { |
||
452 | $compiledExpression = $this->compile($expr->expr); |
||
453 | |||
454 | switch ($compiledExpression->getType()) { |
||
455 | case CompiledExpression::DOUBLE: |
||
456 | $this->context->notice('stupid-cast', "You are trying to cast 'float' to 'float'", $expr); |
||
457 | return $compiledExpression; |
||
458 | case CompiledExpression::BOOLEAN: |
||
459 | case CompiledExpression::INTEGER: |
||
460 | case CompiledExpression::NUMBER: |
||
461 | case CompiledExpression::STRING: |
||
462 | return new CompiledExpression(CompiledExpression::DOUBLE, (float) $compiledExpression->getValue()); |
||
463 | } |
||
464 | |||
465 | return new CompiledExpression(); |
||
466 | } |
||
467 | |||
468 | /** |
||
469 | * (string) {$expr} |
||
470 | * |
||
471 | * @param Node\Expr\Cast\String_ $expr |
||
472 | * @return CompiledExpression |
||
473 | */ |
||
474 | protected function passCastString(Node\Expr\Cast\String_ $expr) |
||
475 | { |
||
476 | $compiledExpression = $this->compile($expr->expr); |
||
477 | |||
478 | switch ($compiledExpression->getType()) { |
||
479 | case CompiledExpression::STRING: |
||
480 | $this->context->notice('stupid-cast', "You are trying to cast 'string' to 'string'", $expr); |
||
481 | return $compiledExpression; |
||
482 | case CompiledExpression::BOOLEAN: |
||
483 | case CompiledExpression::INTEGER: |
||
484 | case CompiledExpression::NUMBER: |
||
485 | case CompiledExpression::DOUBLE: |
||
486 | return new CompiledExpression(CompiledExpression::DOUBLE, (string) $compiledExpression->getValue()); |
||
487 | } |
||
488 | |||
489 | return new CompiledExpression(); |
||
490 | } |
||
491 | |||
492 | /** |
||
493 | * (unset) {$expr} |
||
494 | * |
||
495 | * @param Node\Expr\Cast\Unset_ $expr |
||
496 | * @return CompiledExpression |
||
497 | */ |
||
498 | protected function passCastUnset(Node\Expr\Cast\Unset_ $expr) |
||
499 | { |
||
500 | $compiledExpression = $this->compile($expr->expr); |
||
501 | |||
502 | switch ($compiledExpression->getType()) { |
||
503 | case CompiledExpression::NULL: |
||
504 | $this->context->notice('stupid-cast', "You are trying to cast 'unset' to 'null'", $expr); |
||
505 | return $compiledExpression; |
||
506 | } |
||
507 | |||
508 | return new CompiledExpression(CompiledExpression::NULL, null); |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * @param Node\Expr\PropertyFetch $expr |
||
513 | * @return CompiledExpression |
||
514 | */ |
||
515 | protected function passPropertyFetch(Node\Expr\PropertyFetch $expr) |
||
516 | { |
||
517 | $propertNameCE = $this->compile($expr->name); |
||
518 | |||
519 | $scopeExpression = $this->compile($expr->var); |
||
520 | if ($scopeExpression->isObject()) { |
||
521 | $scopeExpressionValue = $scopeExpression->getValue(); |
||
522 | if ($scopeExpressionValue instanceof ClassDefinition) { |
||
523 | $propertyName = $propertNameCE->isString() ? $propertNameCE->getValue() : false; |
||
524 | if ($propertyName) { |
||
525 | if ($scopeExpressionValue->hasProperty($propertyName, true)) { |
||
526 | $property = $scopeExpressionValue->getProperty($propertyName, true); |
||
527 | return $this->compile($property); |
||
528 | } else { |
||
529 | $this->context->notice( |
||
530 | 'undefined-property', |
||
531 | sprintf( |
||
532 | 'Property %s does not exist in %s scope', |
||
533 | $propertyName, |
||
534 | $scopeExpressionValue->getName() |
||
535 | ), |
||
536 | $expr |
||
537 | ); |
||
538 | } |
||
539 | } |
||
540 | } |
||
541 | |||
542 | return new CompiledExpression(CompiledExpression::UNKNOWN); |
||
543 | } elseif (!$scopeExpression->canBeObject()) { |
||
544 | return new CompiledExpression(CompiledExpression::UNKNOWN); |
||
545 | } |
||
546 | |||
547 | $this->context->notice( |
||
548 | 'property-fetch-on-non-object', |
||
549 | "It's not possible to fetch property on not object", |
||
550 | $expr, |
||
551 | Check::CHECK_BETA |
||
552 | ); |
||
553 | |||
554 | return new CompiledExpression(CompiledExpression::UNKNOWN); |
||
555 | } |
||
556 | |||
557 | /** |
||
558 | * @param Node\Expr\ClassConstFetch $expr |
||
559 | * @return CompiledExpression |
||
560 | */ |
||
561 | protected function passConstFetch(Node\Expr\ClassConstFetch $expr) |
||
583 | |||
584 | /** |
||
585 | * @param Node\Expr\Assign $expr |
||
586 | * @return CompiledExpression |
||
587 | */ |
||
588 | 8 | protected function passSymbol(Node\Expr\Assign $expr) |
|
589 | { |
||
590 | 8 | $compiledExpression = $this->compile($expr->expr); |
|
591 | |||
592 | 8 | if ($expr->var instanceof Node\Expr\List_) { |
|
593 | $isCorrectType = false; |
||
594 | |||
595 | switch ($compiledExpression->getType()) { |
||
596 | case CompiledExpression::ARR: |
||
597 | $isCorrectType = true; |
||
598 | break; |
||
599 | } |
||
600 | |||
601 | if ($expr->var->vars) { |
||
602 | foreach ($expr->var->vars as $key => $var) { |
||
603 | if ($var instanceof Node\Expr\Variable) { |
||
604 | if (!isset($expr->var->name)) { |
||
605 | var_dump($var); |
||
606 | } |
||
607 | $name = $expr->var->name; |
||
608 | |||
609 | $symbol = $this->context->getSymbol($name); |
||
610 | if (!$symbol) { |
||
611 | $symbol = new Variable( |
||
612 | $name, |
||
613 | null, |
||
614 | CompiledExpression::UNKNOWN, |
||
615 | $this->context->getCurrentBranch() |
||
616 | ); |
||
617 | $this->context->addVariable($symbol); |
||
618 | } |
||
619 | |||
620 | if (!$isCorrectType) { |
||
621 | $symbol->modify(CompiledExpression::NULL, null); |
||
622 | } |
||
623 | |||
624 | $symbol->incSets(); |
||
625 | } |
||
626 | } |
||
627 | } |
||
628 | |||
629 | return new CompiledExpression(); |
||
630 | } |
||
631 | |||
632 | 8 | if ($expr->var instanceof Node\Expr\Variable) { |
|
633 | 8 | $name = $expr->var->name; |
|
634 | |||
635 | 8 | $symbol = $this->context->getSymbol($name); |
|
636 | 8 | if ($symbol) { |
|
637 | 2 | $symbol->modify($compiledExpression->getType(), $compiledExpression->getValue()); |
|
638 | 2 | $this->context->modifyReferencedVariables( |
|
639 | 2 | $symbol, |
|
640 | 2 | $compiledExpression->getType(), |
|
641 | 2 | $compiledExpression->getValue() |
|
642 | 2 | ); |
|
643 | 2 | } else { |
|
644 | 8 | $symbol = new Variable( |
|
645 | 8 | $name, |
|
646 | 8 | $compiledExpression->getValue(), |
|
647 | 8 | $compiledExpression->getType(), |
|
648 | 8 | $this->context->getCurrentBranch() |
|
649 | 8 | ); |
|
650 | 8 | $this->context->addVariable($symbol); |
|
651 | } |
||
652 | |||
653 | 8 | $symbol->incSets(); |
|
654 | 8 | return $compiledExpression; |
|
655 | } |
||
656 | |||
657 | if ($expr->var instanceof Node\Expr\PropertyFetch) { |
||
658 | $compiledExpression = $this->compile($expr->var->var); |
||
659 | if ($compiledExpression->getType() == CompiledExpression::OBJECT) { |
||
660 | $objectDefinition = $compiledExpression->getValue(); |
||
661 | if ($objectDefinition instanceof ClassDefinition) { |
||
662 | if (is_string($expr->var->name)) { |
||
663 | if ($objectDefinition->hasProperty($expr->var->name)) { |
||
664 | return $this->compile($objectDefinition->getProperty($expr->var->name)); |
||
665 | } |
||
666 | } |
||
667 | } |
||
668 | } |
||
669 | } |
||
670 | |||
671 | $this->context->debug('Unknown how to pass symbol'); |
||
672 | return new CompiledExpression(); |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * @param Node\Expr\AssignRef $expr |
||
677 | * @return CompiledExpression |
||
678 | */ |
||
679 | 1 | protected function passSymbolByRef(Node\Expr\AssignRef $expr) |
|
680 | { |
||
681 | 1 | if ($expr->var instanceof Node\Expr\Variable) { |
|
682 | 1 | $name = $expr->var->name; |
|
683 | |||
684 | 1 | $compiledExpression = $this->compile($expr->expr); |
|
685 | |||
686 | 1 | $symbol = $this->context->getSymbol($name); |
|
687 | 1 | if ($symbol) { |
|
688 | $symbol->modify($compiledExpression->getType(), $compiledExpression->getValue()); |
||
689 | } else { |
||
690 | 1 | $symbol = new Variable( |
|
691 | 1 | $name, |
|
692 | 1 | $compiledExpression->getValue(), |
|
693 | 1 | $compiledExpression->getType(), |
|
694 | 1 | $this->context->getCurrentBranch() |
|
695 | 1 | ); |
|
696 | 1 | $this->context->addVariable($symbol); |
|
697 | } |
||
698 | |||
699 | 1 | if ($expr->expr instanceof Node\Expr\Variable) { |
|
700 | 1 | $rightVarName = $expr->expr->name; |
|
701 | |||
702 | 1 | $rightSymbol = $this->context->getSymbol($rightVarName); |
|
703 | 1 | if ($rightSymbol) { |
|
704 | 1 | $rightSymbol->incUse(); |
|
705 | 1 | $symbol->setReferencedTo($rightSymbol); |
|
706 | 1 | } else { |
|
707 | $this->context->debug('Cannot fetch variable by name: ' . $rightVarName); |
||
708 | } |
||
709 | 1 | } |
|
710 | |||
711 | 1 | $symbol->incSets(); |
|
712 | 1 | return $compiledExpression; |
|
713 | } |
||
714 | |||
715 | $this->context->debug('Unknown how to pass symbol by ref'); |
||
716 | return new CompiledExpression(); |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * @param Node\Expr\Variable $expr |
||
721 | * @return CompiledExpression |
||
722 | */ |
||
723 | 4 | protected function passExprVariable(Node\Expr\Variable $expr) |
|
739 | |||
740 | /** |
||
741 | * Compile Array_ expression to CompiledExpression |
||
742 | * |
||
743 | * @param Node\Expr\Array_ $expr |
||
744 | * @return CompiledExpression |
||
745 | */ |
||
746 | 20 | protected function getArray(Node\Expr\Array_ $expr) |
|
778 | |||
779 | /** |
||
780 | * Convert const fetch expr to CompiledExpression |
||
781 | * |
||
782 | * @param Node\Expr\ConstFetch $expr |
||
783 | * @return CompiledExpression |
||
784 | */ |
||
785 | 4 | protected function constFetch(Node\Expr\ConstFetch $expr) |
|
786 | { |
||
787 | 4 | if ($expr->name instanceof Node\Name) { |
|
788 | 4 | if ($expr->name->parts[0] === 'true') { |
|
789 | 3 | return new CompiledExpression(CompiledExpression::BOOLEAN, true); |
|
790 | } |
||
791 | |||
792 | 1 | if ($expr->name->parts[0] === 'false') { |
|
793 | return new CompiledExpression(CompiledExpression::BOOLEAN, false); |
||
802 | } |
||
803 |
The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.
Some resources for further reading:
You can also find more detailed suggestions for refactoring in the “Code” section of your repository.