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 QueryBuilder 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 QueryBuilder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class QueryBuilder implements QueryInterface |
||
19 | { |
||
20 | /* @var string The modifier. SELECT, INSERT INTO, UPDATE or DELETE */ |
||
21 | private $modifier; |
||
22 | |||
23 | /* @var string The table name. */ |
||
24 | private $table; |
||
25 | |||
26 | /* @var array The columns. */ |
||
27 | private $columns; |
||
28 | |||
29 | /* @var array The values. */ |
||
30 | private $values; |
||
31 | |||
32 | /* @var array The join conditions. */ |
||
33 | private $join; |
||
34 | |||
35 | /* @var array The where conditions. */ |
||
36 | private $where; |
||
37 | |||
38 | /* @var array The group by conditions. */ |
||
39 | private $groupBy; |
||
40 | |||
41 | /* @var array The order by conditions. */ |
||
42 | private $orderBy; |
||
43 | |||
44 | /* @var string The limit. */ |
||
45 | private $limit; |
||
46 | |||
47 | /* @var string The offset. */ |
||
48 | private $offset; |
||
49 | |||
50 | /** |
||
51 | * Construct a query builder object with the given table. |
||
52 | * |
||
53 | * @param string $table |
||
54 | */ |
||
55 | 45 | public function __construct($table) |
|
63 | |||
64 | /** |
||
65 | * Returns a string representation of the query object. |
||
66 | * |
||
67 | * @return string a string representation of the query object. |
||
68 | */ |
||
69 | 45 | public function __toString() |
|
136 | |||
137 | /** |
||
138 | * {@inheritdoc} |
||
139 | */ |
||
140 | 33 | public function select($columns = ['*']) |
|
147 | |||
148 | /** |
||
149 | * Returns the select clause. |
||
150 | * |
||
151 | * @return string the select clause. |
||
152 | */ |
||
153 | 33 | public function getSelectClause() |
|
157 | |||
158 | /** |
||
159 | * {@inheritdoc} |
||
160 | */ |
||
161 | 3 | public function insert(array $values) |
|
168 | |||
169 | /** |
||
170 | * Returns the insert clause. |
||
171 | * |
||
172 | * @return string the insert clause. |
||
173 | */ |
||
174 | 3 | public function getInsertClause() |
|
186 | |||
187 | /** |
||
188 | * {@inheritdoc} |
||
189 | */ |
||
190 | 4 | public function update(array $values) |
|
197 | |||
198 | /** |
||
199 | * Returns the update clause. |
||
200 | * |
||
201 | * @return string the update clause. |
||
202 | */ |
||
203 | 4 | public function getUpdateClause() |
|
213 | |||
214 | /** |
||
215 | * {@inheritdoc} |
||
216 | */ |
||
217 | 3 | public function delete() |
|
223 | |||
224 | /** |
||
225 | * Returns the delete clause. |
||
226 | * |
||
227 | * @return string the delete clause. |
||
228 | */ |
||
229 | 3 | public function getDeleteClause() |
|
233 | |||
234 | /** |
||
235 | * {@inheritdoc} |
||
236 | */ |
||
237 | 2 | public function join($table, $primary, $operator, $secondary) |
|
243 | |||
244 | /** |
||
245 | * {@inheritdoc} |
||
246 | */ |
||
247 | 2 | public function leftJoin($table, $primary, $operator, $secondary) |
|
253 | |||
254 | /** |
||
255 | * {@inheritdoc} |
||
256 | */ |
||
257 | 2 | public function rightJoin($table, $primary, $operator, $secondary) |
|
263 | |||
264 | /** |
||
265 | * {@inheritdoc} |
||
266 | */ |
||
267 | 2 | public function crossJoin($table, $primary, $operator, $secondary) |
|
273 | |||
274 | 33 | public function getJoinClause() |
|
284 | |||
285 | /** |
||
286 | * {@inheritdoc} |
||
287 | */ |
||
288 | 15 | public function where($column, $operator, $value) |
|
294 | |||
295 | /** |
||
296 | * Returns the where clause. |
||
297 | * |
||
298 | * @return string the where clause. |
||
299 | */ |
||
300 | 40 | private function getWhereClause() |
|
314 | |||
315 | /** |
||
316 | * Returns the where condition. |
||
317 | * |
||
318 | * @param string $column |
||
319 | * @param string $operator |
||
320 | * @param mixed $value |
||
321 | * @return string the where condition. |
||
322 | */ |
||
323 | 15 | private function getWhereCondition($column, $operator, $value) |
|
331 | |||
332 | /** |
||
333 | * {@inheritdoc} |
||
334 | */ |
||
335 | 2 | public function groupBy($column) |
|
341 | |||
342 | /** |
||
343 | * Returns the group by clause. |
||
344 | * |
||
345 | * @return string the group by clause. |
||
346 | */ |
||
347 | 33 | public function getGroupByClause() |
|
355 | |||
356 | /** |
||
357 | * {@inheritdoc} |
||
358 | */ |
||
359 | 4 | public function orderBy($column, $order = null) |
|
371 | |||
372 | /** |
||
373 | * Returns the order by clause. |
||
374 | * |
||
375 | * @return string the order by clause. |
||
376 | */ |
||
377 | 33 | public function getOrderByClause() |
|
385 | |||
386 | /** |
||
387 | * {@inheritdoc} |
||
388 | */ |
||
389 | 6 | public function limit($limit) |
|
395 | |||
396 | /** |
||
397 | * Returns the limit clause. |
||
398 | * |
||
399 | * @return string the limit clause. |
||
400 | */ |
||
401 | 40 | private function getLimitClause() |
|
409 | |||
410 | /** |
||
411 | * {@inheritdoc} |
||
412 | */ |
||
413 | 2 | public function offset($offset) |
|
419 | |||
420 | /** |
||
421 | * Returns the offset clause. |
||
422 | * |
||
423 | * @return string the offset clause. |
||
424 | */ |
||
425 | 33 | private function getOffsetClause() |
|
433 | } |
||
434 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.