Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Value 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 Value, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class Value { |
||
10 | private $baseData; |
||
11 | private $autoLookup; |
||
12 | private $tokens; |
||
|
|||
13 | |||
14 | /* |
||
15 | The next operation to perform. Will be one of the following: |
||
16 | ARG - A new value e.g, "a","b" becomes ["a", "b"] |
||
17 | CONCAT - Concat onto the current arg e.g "a" + "b" becomes ["ab"] |
||
18 | NOT - Boolean operation "a" != "b" becomes [true] |
||
19 | EQUALS - Boolean operation "a" = "b" becomes [false] |
||
20 | */ |
||
21 | private $mode; |
||
22 | |||
23 | /* |
||
24 | Stores the last value e.g. |
||
25 | "a" + "b" |
||
26 | Will store "a" before reading the token for the + and perfoming the concatenate operation |
||
27 | */ |
||
28 | private $last; |
||
29 | private $data; |
||
30 | private $result; |
||
31 | private $element; |
||
32 | |||
33 | private $tokenFuncs = [ |
||
34 | Tokenizer::NOT => 'processComparator', |
||
35 | Tokenizer::EQUALS => 'processComparator', |
||
36 | Tokenizer::DOT => 'processDot', |
||
37 | Tokenizer::OPEN_SQUARE_BRACKET => 'processSquareBracket', |
||
38 | Tokenizer::ARG => 'processSeparator', |
||
39 | Tokenizer::CONCAT => 'processSeparator', |
||
40 | Tokenizer::NAME => 'processScalar', |
||
41 | Tokenizer::NUMERIC => 'processScalar', |
||
42 | Tokenizer::BOOL => 'processScalar', |
||
43 | Tokenizer::STRING => 'processString', |
||
44 | Tokenizer::OPEN_BRACKET => 'processBrackets' |
||
45 | ]; |
||
46 | |||
47 | public function __construct($data, $autoLookup = false) { |
||
51 | |||
52 | public function parse($str, $element = null, $returnTokens = false) { |
||
59 | |||
60 | public function parseTokens($tokens, $element, $data) { |
||
75 | |||
76 | private function processComparator($token) { |
||
84 | |||
85 | |||
86 | //Reads the last selected value from $data regardless if it's an array or object and overrides $this->data with the new value |
||
87 | private function moveLastToData() { |
||
91 | |||
92 | //Dot moves $data to the next object in $data foo.bar moves the $data pointer from `foo` to `bar` |
||
93 | private function processDot($token) { |
||
99 | |||
100 | private function processSquareBracket($token) { |
||
106 | |||
107 | private function processSeparator($token) { |
||
112 | |||
113 | private function processScalar($token) { |
||
116 | |||
117 | private function processString($token) { |
||
120 | |||
121 | private function processBrackets($token) { |
||
138 | |||
139 | private function callTransphpormFunctions($token) { |
||
149 | |||
150 | //Applies the current operation to whatever is in $last based on $mode |
||
151 | private function processLast() { |
||
165 | |||
166 | |||
167 | //Extracts $last from $data. If "last" is "bar" from value "foo.bar", |
||
168 | //$data contains "foo" and this function reads $data[$bar] or $data->$bar |
||
169 | private function extractLast($result) { |
||
178 | |||
179 | //Processes $newValue using $mode. Either concats to the current argument, adds a new argument |
||
180 | //Or usess the two arguments for a boolean comparison |
||
181 | private function processValue($newValue) { |
||
197 | |||
198 | private function callFunc($name, $args, $element, $data) { |
||
202 | |||
203 | private function callFuncOnObject($obj, $func, $args, $element) { |
||
207 | } |
||
208 |
This check marks private properties in classes that are never used. Those properties can be removed.