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 BaseQuery 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 BaseQuery, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | abstract class BaseQuery implements Query { |
||
21 | |||
22 | /** |
||
23 | * Database connection the query is associated with. |
||
24 | * @var DatabaseConnection |
||
25 | */ |
||
26 | protected $db; |
||
27 | |||
28 | /** |
||
29 | * Array of join clauses. |
||
30 | * @var array |
||
31 | */ |
||
32 | protected $joins; |
||
33 | |||
34 | /** |
||
35 | * Array of where clauses. |
||
36 | * @var array |
||
37 | */ |
||
38 | protected $where; |
||
39 | |||
40 | /** |
||
41 | * Array of order by clauses. |
||
42 | * @var array |
||
43 | */ |
||
44 | protected $order; |
||
45 | |||
46 | /** |
||
47 | * Query offset. |
||
48 | * @var integer |
||
49 | */ |
||
50 | protected $offset; |
||
51 | |||
52 | /** |
||
53 | * Query limit. |
||
54 | * @var integer|null |
||
55 | */ |
||
56 | protected $limit; |
||
57 | |||
58 | /** |
||
59 | * Array of query parameters |
||
60 | * @var array |
||
61 | */ |
||
62 | protected $params; |
||
63 | |||
64 | public function __construct( DatabaseConnection $db ) { |
||
73 | |||
74 | public function __toString() { |
||
78 | |||
79 | public function innerJoin( $table, array $on ) { |
||
83 | |||
84 | public function leftJoin( $table, array $on ) { |
||
88 | |||
89 | public function joinRaw( $sql, $parameters = [] ) { |
||
94 | |||
95 | public function where( $column, $operator, $value = null ) { |
||
122 | |||
123 | public function whereArray( array $where ) { |
||
133 | |||
134 | public function whereRaw( $sql, $parameters = [] ) { |
||
139 | |||
140 | public function orderBy( $column, $ascending = true ) { |
||
145 | |||
146 | public function offset( $offset ) { |
||
150 | |||
151 | public function limit( $limit ) { |
||
155 | |||
156 | public function getParameters() { |
||
159 | |||
160 | View Code Duplication | public function setParameters( array $params, $replace = false ) { |
|
167 | |||
168 | /** |
||
169 | * Generate a SQL string as an array. |
||
170 | * @return array |
||
171 | */ |
||
172 | abstract protected function compile(); |
||
173 | |||
174 | protected function compileJoins() { |
||
189 | |||
190 | protected function compileOn( array $on ) { |
||
204 | |||
205 | protected function compileWhere() { |
||
218 | |||
219 | protected function compileOrderBy() { |
||
234 | |||
235 | protected function compileOffsetLimit() { |
||
258 | |||
259 | protected function quoteIdentifier( $spec ) { |
||
277 | |||
278 | /** |
||
279 | * Join an array of values to form a string suitable for use in a SQL IN clause. |
||
280 | * The numeric parameter determines whether values are escaped and quoted; |
||
281 | * a null value (the default) will cause the function to auto-detect whether |
||
282 | * values should be escaped and quoted. |
||
283 | * |
||
284 | * @param array $values |
||
285 | * @param null|boolean $numeric |
||
286 | * @return string |
||
287 | */ |
||
288 | protected function makeInClause( array $values, $numeric = null ) { |
||
304 | |||
305 | protected function getParameterName( $column, $operator ) { |
||
331 | |||
332 | /** |
||
333 | * Add a parameter and return the placeholder to be inserted into the query string. |
||
334 | * @param string $name |
||
335 | * @param mixed $value |
||
336 | * @return string |
||
337 | */ |
||
338 | protected function bindParam( $name, $value ) { |
||
348 | |||
349 | } |
||
350 | |||
351 | // EOF |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.