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 Xhgui_Storage_PDO 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 Xhgui_Storage_PDO, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
5 | class Xhgui_Storage_PDO extends Xhgui_Storage_Abstract implements |
||
6 | \Xhgui_StorageInterface, |
||
7 | \Xhgui_WatchedFunctionsStorageInterface |
||
8 | { |
||
9 | |||
10 | /** |
||
11 | * @var \PDO |
||
12 | */ |
||
13 | protected $connection; |
||
14 | |||
15 | /** |
||
16 | * @var bool |
||
17 | */ |
||
18 | protected $jsonMode = false; |
||
19 | |||
20 | /** |
||
21 | * PDO constructor. |
||
22 | * @param $config |
||
23 | */ |
||
24 | public function __construct($config) |
||
41 | |||
42 | /** |
||
43 | * @inheritDoc |
||
44 | * @param \Xhgui_Storage_Filter $filter |
||
45 | * @param bool $projections |
||
46 | * @return \Xhgui_Storage_ResultSet |
||
47 | */ |
||
48 | public function find(\Xhgui_Storage_Filter $filter, $projections = false) |
||
49 | { |
||
50 | list($query, $params) = $this->getQuery($filter, false); |
||
51 | |||
52 | try { |
||
53 | $stmt = $this->connection->prepare($query); |
||
54 | $stmt->execute($params); |
||
55 | } catch (\Exception $e) { |
||
56 | print_r($e->getMessage()); |
||
57 | exit; |
||
58 | } |
||
59 | |||
60 | $tmp = []; |
||
61 | while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { |
||
62 | $meta = json_decode($row['meta'], true); |
||
63 | View Code Duplication | if ($filter->getCookie()) { |
|
64 | // because cookie is not parsed and stored in separate structure we need to double check if |
||
65 | // value that we search is in fact in http cookie server field. SQL filter only checks whole |
||
66 | // meta |
||
67 | if (strpos($meta['SERVER']['HTTP_COOKIE'], $filter->getCookie()) === false) { |
||
68 | continue; |
||
69 | } |
||
70 | } |
||
71 | $tmp[$row['id']] = $row; |
||
72 | $tmp[$row['id']]['profile'] = json_decode($row['profiles'], true); |
||
73 | $tmp[$row['id']]['meta'] = $meta; |
||
74 | } |
||
75 | |||
76 | return new \Xhgui_Storage_ResultSet($tmp); |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * Get query that is used for both list and count |
||
81 | * |
||
82 | * @param \Xhgui_Storage_Filter $filter |
||
83 | * @param bool $count |
||
84 | * @return array |
||
85 | */ |
||
86 | protected function getQuery(\Xhgui_Storage_Filter $filter, $count = false) |
||
244 | |||
245 | /** |
||
246 | * @inheritDoc |
||
247 | * @param Xhgui_Storage_Filter $filter |
||
248 | * @param $col |
||
249 | * @param int $percentile |
||
250 | * @return array |
||
251 | * @throws Exception |
||
252 | */ |
||
253 | public function aggregate(\Xhgui_Storage_Filter $filter, $col, $percentile = 1) |
||
293 | |||
294 | /** |
||
295 | * @inheritDoc |
||
296 | * @@param Xhgui_Storage_Filter $filter |
||
297 | * @return int |
||
298 | */ |
||
299 | public function count(\Xhgui_Storage_Filter $filter) |
||
317 | |||
318 | /** |
||
319 | * @inheritDoc |
||
320 | * @param $id |
||
321 | * @return mixed |
||
322 | */ |
||
323 | public function findOne($id) |
||
344 | |||
345 | /** |
||
346 | * @inheritDoc |
||
347 | * @param $id |
||
348 | */ |
||
349 | public function remove($id) |
||
367 | |||
368 | /** |
||
369 | * @inheritDoc |
||
370 | * Remove all data from profile tables |
||
371 | */ |
||
372 | public function drop() |
||
378 | |||
379 | /** |
||
380 | * @inheritDoc |
||
381 | * @return array |
||
382 | */ |
||
383 | public function getWatchedFunctions() |
||
388 | |||
389 | /** |
||
390 | * @inheritDoc |
||
391 | * @param $name |
||
392 | * @return bool |
||
393 | */ |
||
394 | public function addWatchedFunction($name) |
||
404 | |||
405 | /** |
||
406 | * @inheritDoc |
||
407 | * @param $id |
||
408 | * @param $name |
||
409 | */ |
||
410 | public function updateWatchedFunction($id, $name) |
||
415 | |||
416 | /** |
||
417 | * @inheritDoc |
||
418 | * @param $id |
||
419 | */ |
||
420 | public function removeWatchedFunction($id) |
||
425 | |||
426 | /** |
||
427 | * This method will look into json stored data in native way (if db supports that) and it will match row based on that. |
||
428 | * |
||
429 | * @todo this should be moved to engine specific storage classes in the future. |
||
430 | * @param array $where |
||
431 | * @param array $params |
||
432 | * @param $field |
||
433 | * @param $value |
||
434 | * @param $fieldToLookIn |
||
435 | * @param array $path |
||
436 | * @return array |
||
437 | */ |
||
438 | protected function compareWithJson(array $where, array $params, $field, $value, $fieldToLookIn, array $path) |
||
460 | } |
||
461 |
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.