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 | 375 | public function __construct(Context $context, EventManager $eventManager) |
|
40 | |||
41 | /** |
||
42 | * @param $expr |
||
43 | * @return ExpressionCompilerInterface|AbstractExpressionCompiler |
||
44 | */ |
||
45 | 364 | protected function factory($expr) |
|
46 | { |
||
47 | 364 | switch (get_class($expr)) { |
|
48 | /** |
||
49 | * Call(s) |
||
50 | */ |
||
51 | 364 | case Node\Expr\MethodCall::class: |
|
52 | return new Expression\MethodCall(); |
||
53 | 364 | case Node\Expr\FuncCall::class: |
|
54 | 7 | return new Expression\FunctionCall(); |
|
55 | 358 | case Node\Expr\StaticCall::class: |
|
56 | return new Expression\StaticCall(); |
||
57 | /** |
||
58 | * Operators |
||
59 | */ |
||
60 | 358 | case Node\Expr\New_::class: |
|
61 | return new Expression\Operators\NewOp(); |
||
62 | 358 | case Node\Expr\Instanceof_::class: |
|
63 | return new Expression\Operators\InstanceOfOp(); |
||
64 | /** |
||
65 | * Assign |
||
66 | */ |
||
67 | 358 | case Node\Expr\AssignOp\Pow::class: |
|
68 | return new Expression\AssignOp\Pow(); |
||
69 | 358 | case Node\Expr\AssignOp\Plus::class: |
|
70 | return new Expression\AssignOp\Plus(); |
||
71 | 358 | case Node\Expr\AssignOp\Minus::class: |
|
72 | return new Expression\AssignOp\Minus(); |
||
73 | 358 | case Node\Expr\AssignOp\Mod::class: |
|
74 | return new Expression\AssignOp\Mod(); |
||
75 | 358 | case Node\Expr\AssignOp\BitwiseOr::class: |
|
76 | return new Expression\AssignOp\BitwiseOr(); |
||
77 | 358 | case Node\Expr\AssignOp\BitwiseAnd::class: |
|
78 | return new Expression\AssignOp\BitwiseAnd(); |
||
79 | /** |
||
80 | * BinaryOp |
||
81 | */ |
||
82 | 358 | case Node\Expr\BinaryOp\Identical::class: |
|
83 | 28 | return new Expression\BinaryOp\Identical(); |
|
84 | 330 | case Node\Expr\BinaryOp\Concat::class: |
|
85 | 1 | return new Expression\Operators\Concat(); |
|
86 | 329 | case Node\Expr\BinaryOp\NotIdentical::class: |
|
87 | 14 | return new Expression\BinaryOp\NotIdentical(); |
|
88 | 315 | case Node\Expr\BinaryOp\Equal::class: |
|
89 | 34 | return new Expression\BinaryOp\Equal(); |
|
90 | 281 | 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 | 264 | case Node\Expr\PostInc::class: |
|
96 | 4 | return new Expression\Operators\PostInc(); |
|
97 | 260 | case Node\Expr\PostDec::class: |
|
98 | 4 | return new Expression\Operators\PostDec(); |
|
99 | /** |
||
100 | * Arithmetical |
||
101 | */ |
||
102 | 256 | case Node\Expr\BinaryOp\Div::class: |
|
103 | 37 | return new Expression\Operators\Arithmetical\Div(); |
|
104 | 219 | case Node\Expr\BinaryOp\Plus::class: |
|
105 | 45 | return new Expression\Operators\Arithmetical\Plus(); |
|
106 | 174 | case Node\Expr\BinaryOp\Minus::class: |
|
107 | 18 | return new Expression\Operators\Arithmetical\Minus(); |
|
108 | 156 | case Node\Expr\BinaryOp\Mul::class: |
|
109 | 35 | return new Expression\Operators\Arithmetical\Mul(); |
|
110 | 121 | 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 | 86 | case Node\Expr\BinaryOp\BitwiseOr::class: |
|
117 | return new Expression\Operators\Bitwise\BitwiseOr(); |
||
118 | 86 | case Node\Expr\BinaryOp\BitwiseXor::class: |
|
119 | return new Expression\Operators\Bitwise\BitwiseXor(); |
||
120 | 86 | case Node\Expr\BinaryOp\BitwiseAnd::class: |
|
121 | return new Expression\Operators\Bitwise\BitwiseAnd(); |
||
122 | 86 | case Node\Expr\BinaryOp\ShiftRight::class: |
|
123 | return new Expression\Operators\Bitwise\ShiftRight(); |
||
124 | 86 | case Node\Expr\BinaryOp\ShiftLeft::class: |
|
125 | return new Expression\Operators\Bitwise\ShiftLeft(); |
||
126 | 86 | case Node\Expr\BitwiseNot::class: |
|
127 | return new Expression\Operators\Bitwise\BitwiseNot(); |
||
128 | /** |
||
129 | * Logical |
||
130 | */ |
||
131 | 86 | case Node\Expr\BinaryOp\BooleanOr::class: |
|
132 | 10 | return new Expression\Operators\Logical\BooleanOr(); |
|
133 | 76 | case Node\Expr\BinaryOp\BooleanAnd::class: |
|
134 | 5 | return new Expression\Operators\Logical\BooleanAnd(); |
|
135 | 71 | case Node\Expr\BooleanNot::class: |
|
136 | 5 | return new Expression\Operators\Logical\BooleanNot(); |
|
137 | /** |
||
138 | * Comparison |
||
139 | */ |
||
140 | 66 | case Node\Expr\BinaryOp\Greater::class: |
|
141 | 12 | return new Expression\Operators\Comparison\Greater(); |
|
142 | 54 | case Node\Expr\BinaryOp\GreaterOrEqual::class: |
|
143 | 12 | return new Expression\Operators\Comparison\GreaterOrEqual(); |
|
144 | 42 | case Node\Expr\BinaryOp\Smaller::class: |
|
145 | 12 | return new Expression\Operators\Comparison\Smaller(); |
|
146 | 30 | case Node\Expr\BinaryOp\SmallerOrEqual::class: |
|
147 | 12 | return new Expression\Operators\Comparison\SmallerOrEqual(); |
|
148 | /** |
||
149 | * Another |
||
150 | */ |
||
151 | 18 | case Node\Expr\Closure::class: |
|
152 | return new Expression\Closure(); |
||
153 | 18 | case Node\Expr\UnaryMinus::class: |
|
154 | 9 | return new Expression\Operators\UnaryMinus(); |
|
155 | 9 | case Node\Expr\UnaryPlus::class: |
|
156 | 9 | return new Expression\Operators\UnaryPlus(); |
|
157 | } |
||
158 | |||
159 | return false; |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * @param object|string $expr |
||
164 | * @return CompiledExpression |
||
165 | */ |
||
166 | 375 | public function compile($expr) |
|
261 | |||
262 | /** |
||
263 | * @todo Implement |
||
264 | * |
||
265 | * @param Node\Stmt\Property $st |
||
266 | * @return CompiledExpression |
||
267 | */ |
||
268 | public function passProperty(Node\Stmt\Property $st) |
||
328 | |||
329 | /** |
||
330 | * @param Node\Expr\Variable $expr |
||
331 | * @return CompiledExpression |
||
332 | */ |
||
333 | public function declareVariable(Node\Expr\Variable $expr) |
||
343 | |||
344 | /** |
||
345 | * @param Node\Name\FullyQualified $expr |
||
346 | * @return CompiledExpression |
||
347 | */ |
||
348 | public function getFullyQualifiedNodeName(Node\Name\FullyQualified $expr) |
||
354 | |||
355 | /** |
||
356 | * @param Node\Name $expr |
||
357 | * @return CompiledExpression |
||
358 | */ |
||
359 | 7 | public function getNodeName(Node\Name $expr) |
|
394 | |||
395 | /** |
||
396 | * (bool) {$expr} |
||
397 | * |
||
398 | * @param Node\Expr\Cast\Bool_ $expr |
||
399 | * @return CompiledExpression |
||
400 | */ |
||
401 | protected function passCastBoolean(Node\Expr\Cast\Bool_ $expr) |
||
418 | |||
419 | /** |
||
420 | * (int) {$expr} |
||
421 | * |
||
422 | * @param Node\Expr\Cast\Int_ $expr |
||
423 | * @return CompiledExpression |
||
424 | */ |
||
425 | protected function passCastInt(Node\Expr\Cast\Int_ $expr) |
||
426 | { |
||
427 | $compiledExpression = $this->compile($expr->expr); |
||
428 | |||
429 | switch ($compiledExpression->getType()) { |
||
430 | case CompiledExpression::INTEGER: |
||
431 | $this->context->notice('stupid-cast', "You are trying to cast 'int' to 'int'", $expr); |
||
432 | return $compiledExpression; |
||
433 | case CompiledExpression::BOOLEAN: |
||
434 | case CompiledExpression::DOUBLE: |
||
435 | case CompiledExpression::NUMBER: |
||
436 | case CompiledExpression::STRING: |
||
437 | return new CompiledExpression(CompiledExpression::INTEGER, (int) $compiledExpression->getValue()); |
||
438 | } |
||
439 | |||
440 | return new CompiledExpression(); |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * (float) {$expr} |
||
445 | * |
||
446 | * @param Node\Expr\Cast\Double $expr |
||
447 | * @return CompiledExpression |
||
448 | */ |
||
449 | protected function passCastFloat(Node\Expr\Cast\Double $expr) |
||
450 | { |
||
451 | $compiledExpression = $this->compile($expr->expr); |
||
452 | |||
453 | switch ($compiledExpression->getType()) { |
||
454 | case CompiledExpression::DOUBLE: |
||
455 | $this->context->notice('stupid-cast', "You are trying to cast 'float' to 'float'", $expr); |
||
456 | return $compiledExpression; |
||
457 | case CompiledExpression::BOOLEAN: |
||
458 | case CompiledExpression::INTEGER: |
||
459 | case CompiledExpression::NUMBER: |
||
460 | case CompiledExpression::STRING: |
||
461 | return new CompiledExpression(CompiledExpression::DOUBLE, (float) $compiledExpression->getValue()); |
||
462 | } |
||
463 | |||
464 | return new CompiledExpression(); |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * (string) {$expr} |
||
469 | * |
||
470 | * @param Node\Expr\Cast\String_ $expr |
||
471 | * @return CompiledExpression |
||
472 | */ |
||
473 | protected function passCastString(Node\Expr\Cast\String_ $expr) |
||
474 | { |
||
475 | $compiledExpression = $this->compile($expr->expr); |
||
476 | |||
477 | switch ($compiledExpression->getType()) { |
||
478 | case CompiledExpression::STRING: |
||
479 | $this->context->notice('stupid-cast', "You are trying to cast 'string' to 'string'", $expr); |
||
480 | return $compiledExpression; |
||
481 | case CompiledExpression::BOOLEAN: |
||
482 | case CompiledExpression::INTEGER: |
||
483 | case CompiledExpression::NUMBER: |
||
484 | case CompiledExpression::DOUBLE: |
||
485 | return new CompiledExpression(CompiledExpression::DOUBLE, (string) $compiledExpression->getValue()); |
||
486 | } |
||
487 | |||
488 | return new CompiledExpression(); |
||
489 | } |
||
490 | |||
491 | /** |
||
492 | * (unset) {$expr} |
||
493 | * |
||
494 | * @param Node\Expr\Cast\Unset_ $expr |
||
495 | * @return CompiledExpression |
||
496 | */ |
||
497 | protected function passCastUnset(Node\Expr\Cast\Unset_ $expr) |
||
509 | |||
510 | /** |
||
511 | * @param Node\Expr\PropertyFetch $expr |
||
512 | * @return CompiledExpression |
||
513 | */ |
||
514 | protected function passPropertyFetch(Node\Expr\PropertyFetch $expr) |
||
555 | |||
556 | /** |
||
557 | * @param Node\Expr\ClassConstFetch $expr |
||
558 | * @return CompiledExpression |
||
559 | */ |
||
560 | protected function passConstFetch(Node\Expr\ClassConstFetch $expr) |
||
582 | |||
583 | /** |
||
584 | * @param Node\Expr\Assign $expr |
||
585 | * @return CompiledExpression |
||
586 | */ |
||
587 | 5 | protected function passSymbol(Node\Expr\Assign $expr) |
|
673 | |||
674 | /** |
||
675 | * @param Node\Expr\AssignRef $expr |
||
676 | * @return CompiledExpression |
||
677 | */ |
||
678 | 1 | protected function passSymbolByRef(Node\Expr\AssignRef $expr) |
|
717 | |||
718 | /** |
||
719 | * @param Node\Expr\Variable $expr |
||
720 | * @return CompiledExpression |
||
721 | */ |
||
722 | 3 | protected function passExprVariable(Node\Expr\Variable $expr) |
|
738 | |||
739 | /** |
||
740 | * Compile Array_ expression to CompiledExpression |
||
741 | * |
||
742 | * @param Node\Expr\Array_ $expr |
||
743 | * @return CompiledExpression |
||
744 | */ |
||
745 | 12 | protected function getArray(Node\Expr\Array_ $expr) |
|
777 | |||
778 | /** |
||
779 | * Convert const fetch expr to CompiledExpression |
||
780 | * |
||
781 | * @param Node\Expr\ConstFetch $expr |
||
782 | * @return CompiledExpression |
||
783 | */ |
||
784 | 2 | protected function constFetch(Node\Expr\ConstFetch $expr) |
|
801 | } |
||
802 |
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.