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 CHTMLTable 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 CHTMLTable, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
17 | class CHTMLTable |
||
18 | { |
||
19 | const FOOTER = 'footer'; |
||
20 | |||
21 | private $tableSpec; |
||
22 | private $tableHead; |
||
23 | private $tableBody; |
||
24 | private $tableFoot; |
||
25 | |||
26 | /** |
||
27 | * Constructor |
||
28 | * |
||
29 | * Creates a table with table head, table body and if specified, a table |
||
30 | * footer. It is possible to specify the table and the tabel cells settings |
||
31 | * per column. |
||
32 | * |
||
33 | * @param string[] $tableSpecs table settings. |
||
34 | * @param mixed[] $data table cell data. |
||
35 | * @param mixed[] $columnSpecs table columns cell settings. |
||
36 | */ |
||
37 | 11 | public function __construct($tableSpecs = [], $data = [], $columnSpecs = []) |
|
41 | |||
42 | /** |
||
43 | * Creates a table with cell data. |
||
44 | * |
||
45 | * Creates a table with table head, table body with table data and if |
||
46 | * specified, a table footer. It is possible to specify the table and the |
||
47 | * tabel cells settings per column. |
||
48 | * |
||
49 | * @param string[] $tableSpecs table settings. |
||
50 | * @param mixed[] $data table cell data. |
||
51 | * @param mixed[] $columnSpecs table columns cell settings. |
||
52 | * |
||
53 | * @return object the html table object. |
||
54 | */ |
||
55 | 11 | public function create($tableSpecs = [], $data = [], $columnSpecs = []) |
|
66 | |||
67 | /** |
||
68 | * Helper method to reset main parts of table tags. |
||
69 | * |
||
70 | * Sets the table head, table body and table foot tag to null. |
||
71 | * |
||
72 | * @return void |
||
73 | */ |
||
74 | 11 | private function resetTableTags() |
|
80 | |||
81 | /** |
||
82 | * Helper method to set the table specifications. |
||
83 | * |
||
84 | * Merges the table specifications with the default specifications. |
||
85 | * Default table CSS id is html-table. |
||
86 | * |
||
87 | * @param string[] $tableSpec the table specification. |
||
88 | * |
||
89 | * @return void |
||
90 | */ |
||
91 | 11 | private function setTableSpecifications($tableSpec) |
|
104 | |||
105 | /** |
||
106 | * Helper method to check if a CSS class tag is present |
||
107 | * |
||
108 | * Checks if a CSS class tag is present in the table specification. |
||
109 | * |
||
110 | * @param string[] $tableSpec the table specification. |
||
111 | * |
||
112 | * @return boolean true if class is present in the table specification, |
||
113 | * false otherwise. |
||
114 | */ |
||
115 | 11 | private function isClassPresent($tableSpec) |
|
119 | |||
120 | /** |
||
121 | * Helper method to reset the id tag. |
||
122 | * |
||
123 | * Sets the CSS id tag to null. |
||
124 | * |
||
125 | * @param string[] $tableSpec the table specification. |
||
126 | * |
||
127 | * @return string[] the table specification without the CSS id tag. |
||
128 | */ |
||
129 | 1 | private function removeId($tableSpec) { |
|
134 | |||
135 | /** |
||
136 | * Helper method to create the table head. |
||
137 | * |
||
138 | * Creates the table head. The title of the columns are set according to |
||
139 | * the table tag in the column specifications. Otherwise, the title is set |
||
140 | * to the keys name in the table cell data array. |
||
141 | * |
||
142 | * @param mixed[] $data table cell data. |
||
143 | * @param mixed[] $columnSpecs table columns cell settings. |
||
144 | * |
||
145 | * @return void |
||
146 | */ |
||
147 | 11 | private function createTableHead($data, $columnSpecs) |
|
162 | |||
163 | /** |
||
164 | * Helper method to set the column titles from the data array. |
||
165 | * |
||
166 | * Uses the first row in the table cell data array to set the titles of |
||
167 | * the columns. The name of the columns are the key name for the objects in |
||
168 | * the array containing data for the table. |
||
169 | * |
||
170 | * @param mixed[] $data table cell data. |
||
171 | * |
||
172 | * @return void |
||
173 | */ |
||
174 | 11 | private function setColumnTitlesFromData($data) |
|
183 | |||
184 | /** |
||
185 | * Helper method to set the column titles from column specifications. |
||
186 | * |
||
187 | * Uses column specifications to set the name of the columns in the table |
||
188 | * head. |
||
189 | * |
||
190 | * @param mixed[] $columnSpecs table columns cell settings |
||
191 | * |
||
192 | * @return void |
||
193 | */ |
||
194 | 7 | private function setColumnTitlesFromColumnSpecifications($columnSpecs) |
|
204 | |||
205 | /** |
||
206 | * Helper method to check if the column cell belongs to the footer. |
||
207 | * |
||
208 | * Checks the type tag, in the column specification for one column, if the |
||
209 | * tag is present and set to footer. |
||
210 | * |
||
211 | * @param mixed[] $columnSpec cell settings for one column. |
||
212 | * |
||
213 | * @return boolean true if the cell type belongs to the footer, false otherwise. |
||
214 | */ |
||
215 | 7 | private function isTableFooter($columnSpec) |
|
226 | |||
227 | /** |
||
228 | * Helper method to get title from a column specification, if specified. |
||
229 | * |
||
230 | * Uses the title tag in the column specification for one column to get |
||
231 | * the title. If the title tag is not set, the title is the key for the |
||
232 | * objects int the array containing data for the table. |
||
233 | * |
||
234 | * @param string $key the name of the key for the table cell data. |
||
235 | * @param mixed[] $columnSpec cell settings for one column. |
||
236 | * |
||
237 | * @return string[] the name from the title tag in the cell specification. |
||
238 | * Otherwise, the table cell data key name. |
||
239 | */ |
||
240 | 7 | private function getTitle($key, $columnSpec) |
|
244 | |||
245 | /** |
||
246 | * Helper method to create the table body with table cell data. |
||
247 | * |
||
248 | * Sets the table cell data in the table body. |
||
249 | * |
||
250 | * @param mixed[] $data table cell data. |
||
251 | * @param mixed[] $columnSpecs table columns cell settings. |
||
252 | * |
||
253 | * @return void |
||
254 | */ |
||
255 | 11 | private function createTableBody($data, $columnSpecs) |
|
262 | |||
263 | /** |
||
264 | * Helper method to set table data in table body. |
||
265 | * |
||
266 | * Sets table data according to the column specifications, if it is |
||
267 | * specified. Otherwise it sets the data as it is stored in the data array. |
||
268 | * |
||
269 | * @param mixed[] $data table cell data. |
||
270 | * @param mixed[] $columnSpecs table columns cell settings. |
||
271 | * |
||
272 | * @return void |
||
273 | */ |
||
274 | 11 | private function setTableData($data, $columnSpecs) |
|
282 | |||
283 | /** |
||
284 | * Helper method to set table data from the data array. |
||
285 | * |
||
286 | * Sets table data from the data array. |
||
287 | * |
||
288 | * @param mixed[] $data table cell data. |
||
289 | * |
||
290 | * @return void |
||
291 | */ |
||
292 | 11 | private function setTableDataFromData($data) |
|
304 | |||
305 | /** |
||
306 | * Helper method to set table data according to the column specifications. |
||
307 | * |
||
308 | * Sets the table data according to the column specifications, if the cell |
||
309 | * does not belong to the footer. Adds a colspan tag, if it is specified |
||
310 | * for the cell in the column. |
||
311 | * |
||
312 | * @param mixed[] $data table cell data. |
||
313 | * @param mixed[] $columnSpecs table columns cell settings. |
||
314 | * |
||
315 | * @return void |
||
316 | */ |
||
317 | 7 | private function setTableDataAsSpecified($data, $columnSpecs) |
|
332 | |||
333 | /** |
||
334 | * Helper method to get the colspan value, if specified in the column |
||
335 | * specification for the cell. |
||
336 | * |
||
337 | * @param mixed[] $columnSpec cell settings for one column. |
||
338 | * |
||
339 | * @return int the colspan value if specified. Otherwise null. |
||
340 | */ |
||
341 | 7 | private function getColspan($columnSpec) |
|
345 | |||
346 | /** |
||
347 | * Helper method to get the value for a specific position in one row in |
||
348 | * the data array. |
||
349 | * |
||
350 | * Gets the data from a specific position in one row in the data array. |
||
351 | * If a function is specified for the cell in the column, the data is |
||
352 | * runned through the function before it is returned.If the object key is |
||
353 | * specified to object, the reference to the object is fetched from the |
||
354 | * array of objects. |
||
355 | * |
||
356 | * @param object $row one row of in the array of table data. |
||
357 | * @param string $key the name of the key in the associative data array. |
||
358 | * @param mixed[] $columnSpec cell settings for one column. |
||
359 | */ |
||
360 | 7 | private function getValue($row, $key, $columnSpec) |
|
374 | |||
375 | /** |
||
376 | * Helper method t check if the function tag is specified for the cells in |
||
377 | * one column. |
||
378 | * |
||
379 | * Checks if the function tag is set for the cell in one column. |
||
380 | * |
||
381 | * @param mixed[] $columnSpec cell settings for one column. |
||
382 | * |
||
383 | * @return boolean true if a function is connected to the cell, false otherwise. |
||
384 | */ |
||
385 | 7 | private function isFunctionSpecified($columnSpec) |
|
389 | |||
390 | /** |
||
391 | * Helper method to check if the object key is specified to object. |
||
392 | * |
||
393 | * Checks if the object key starts with object. The check is case insensitive. |
||
394 | * |
||
395 | * @param string $key the name of the key for the object. |
||
396 | * |
||
397 | * @return boolean true if the key starts with object, false otherwise. |
||
398 | */ |
||
399 | 3 | private function isObjectSpecifiedAsKey($key) |
|
405 | |||
406 | /** |
||
407 | * Helper method to run the value through a function before it is returned. |
||
408 | * |
||
409 | * Runs the value through a function, if a function is connected to the cell |
||
410 | * in the column. If not function is connected to the cell through the |
||
411 | * column specification, the value is returned as it is. |
||
412 | * |
||
413 | * WHEN USING A FUNCTION, NO DATA IS CHECKED. TO BE PROTECTED AGAINST |
||
414 | * HARMFUL DATA, THE PROTECTION MUST BE ADDED WHEN THE FUNCTION IS SPECIFIED |
||
415 | * WHEN CREATING THE TABLE! |
||
416 | * |
||
417 | * @param mixed[] $columnSpec cell settings for one column |
||
418 | * @param mixed $dataValue the value to run through function, if specified. |
||
419 | * |
||
420 | * @return the value. |
||
421 | */ |
||
422 | 3 | private function getValueThroughFunction($columnSpec, $dataValue) |
|
430 | |||
431 | /** |
||
432 | * Helper method to create table footer with data. |
||
433 | * |
||
434 | * Creates table footer if the cell settings for the column is set to |
||
435 | * footer in the column specifications. |
||
436 | * Adds a colspan tag, if it is specified for the cell in the column. |
||
437 | * |
||
438 | * @param mixed[] $columnSpecs table columns cell settings. |
||
439 | * |
||
440 | * @return void |
||
441 | */ |
||
442 | 11 | private function createTableFooter($columnSpecs) |
|
457 | |||
458 | /** |
||
459 | * Helper method to get table footer data. |
||
460 | * |
||
461 | * Gets table footer data from the column specification. Checks if the |
||
462 | * value should be fetched from a function or from the value tag. |
||
463 | * If either the function or the value specified, an empty string is |
||
464 | * returned. |
||
465 | * |
||
466 | * @param mixed[] $columnSpec cell settings for one column. |
||
467 | * |
||
468 | * @return mixed the cell data value. |
||
469 | */ |
||
470 | 2 | private function getFooterData($columnSpec) |
|
478 | |||
479 | /** |
||
480 | * Gets the table. |
||
481 | * |
||
482 | * Gets the table with table data. |
||
483 | * |
||
484 | * @return html the table with table data. |
||
485 | */ |
||
486 | 11 | public function getHTMLTable() |
|
501 | } |
||
502 |
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.