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:
1 | <?php |
||
13 | final class DatabaseHandler |
||
14 | { |
||
15 | /** |
||
16 | * Cache table name |
||
17 | */ |
||
18 | const TABLE_CACHE = 'robotstxt__cache1'; |
||
19 | |||
20 | /** |
||
21 | * Delay table name |
||
22 | */ |
||
23 | const TABLE_DELAY = 'robotstxt__delay0'; |
||
24 | |||
25 | /** |
||
26 | * MySQL driver name |
||
27 | */ |
||
28 | const DRIVER_MYSQL = 'mysql'; |
||
29 | |||
30 | /** |
||
31 | * Configuration data |
||
32 | */ |
||
33 | private $config = [ |
||
34 | null => [ // Class initialization |
||
35 | self::DRIVER_MYSQL => [ |
||
36 | 'session_get' => 'SELECT @robotstxt;', |
||
37 | 'session_set' => 'SET @robotstxt = 1;', |
||
38 | ], |
||
39 | ], |
||
40 | self::TABLE_CACHE => [ |
||
41 | 'readme' => 'https://github.com/VIPnytt/RobotsTxtParser/blob/master/docs/sql/cache.md', |
||
42 | self::DRIVER_MYSQL => [ |
||
43 | 'file' => __DIR__ . '/../../res/Cache/MySQL.sql', |
||
44 | 'query' => 'SELECT 1 FROM robotstxt__cache1 LIMIT 1;', |
||
45 | 'session_get' => 'SELECT @robotstxt_cache;', |
||
46 | 'session_set' => 'SET @robotstxt_cache = 1;', |
||
47 | ], |
||
48 | ], |
||
49 | self::TABLE_DELAY => [ |
||
50 | 'readme' => 'https://github.com/VIPnytt/RobotsTxtParser/blob/master/docs/sql/delay.md', |
||
51 | self::DRIVER_MYSQL => [ |
||
52 | 'file' => __DIR__ . '/../../res/Delay/MySQL.sql', |
||
53 | 'query' => 'SELECT 1 FROM robotstxt__delay0 LIMIT 1;', |
||
54 | 'session_get' => 'SELECT @robotstxt_delay;', |
||
55 | 'session_set' => 'SET @robotstxt_delay = 1;', |
||
56 | ], |
||
57 | ] |
||
58 | ]; |
||
59 | |||
60 | /** |
||
61 | * Database handler |
||
62 | * @var PDO |
||
63 | */ |
||
64 | private $pdo; |
||
65 | |||
66 | /** |
||
67 | * Driver |
||
68 | * @var string |
||
69 | */ |
||
70 | private $driver; |
||
71 | |||
72 | /** |
||
73 | * Delay manager |
||
74 | * @var Client\Delay\ManagerInterface |
||
75 | */ |
||
76 | private $delayManager; |
||
77 | |||
78 | /** |
||
79 | * DriverHandler constructor. |
||
80 | * |
||
81 | * @param PDO $pdo |
||
82 | */ |
||
83 | public function __construct(PDO $pdo) |
||
97 | |||
98 | /** |
||
99 | * Get session variable |
||
100 | * |
||
101 | * @param string|null $table |
||
102 | * @return bool |
||
103 | */ |
||
104 | private function hasSessionVar($table) |
||
105 | { |
||
106 | if (!isset($this->config[$table][$this->driver]['session_get'])) { |
||
107 | return false; |
||
108 | } |
||
109 | $query = $this->pdo->query($this->config[$table][$this->driver]['session_get']); |
||
110 | return ( |
||
111 | $query->rowCount() > 0 && |
||
112 | $query->fetchColumn(0) !== null |
||
113 | ); |
||
114 | } |
||
115 | |||
116 | /** |
||
117 | * Driver special treatment |
||
118 | * |
||
119 | * @return bool |
||
120 | */ |
||
121 | private function driverDependents() |
||
130 | |||
131 | /** |
||
132 | * Set session variable |
||
133 | * |
||
134 | * @param string|null $table |
||
135 | * @return bool |
||
136 | */ |
||
137 | private function setSessionVar($table) |
||
144 | |||
145 | /** |
||
146 | * Delay client |
||
147 | * |
||
148 | * @param string $baseUri |
||
149 | * @param string $userAgent |
||
150 | * @param float|int $delay |
||
151 | * @return Client\Delay\ClientInterface |
||
152 | * @throws DatabaseException |
||
153 | */ |
||
154 | View Code Duplication | public function delayClient($baseUri, $userAgent, $delay) |
|
163 | |||
164 | /** |
||
165 | * Initial table setup check |
||
166 | * |
||
167 | * @param string $table |
||
168 | * @return bool |
||
169 | * @throws DatabaseException |
||
170 | */ |
||
171 | private function initialCheck($table) |
||
172 | { |
||
173 | if ($this->hasSessionVar($table)) { |
||
174 | return true; |
||
175 | } |
||
176 | try { |
||
177 | $this->pdo->query($this->config[$table][$this->driver]['query']); |
||
178 | } catch (\Exception $exception1) { |
||
179 | try { |
||
180 | $this->pdo->query(file_get_contents($this->config[$table][$this->driver]['file'])); |
||
181 | } catch (\Exception $exception2) { |
||
182 | throw new DatabaseException('Missing table `' . $table . '`. Setup instructions: ' . $this->config[$table]['readme']); |
||
183 | } |
||
184 | } |
||
185 | $this->setSessionVar($table); |
||
186 | return true; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Cache manager |
||
191 | * |
||
192 | * @param array $curlOptions |
||
193 | * @param int|null $byteLimit |
||
194 | * @return Client\Cache\MySQL\Manager |
||
195 | * @throws DatabaseException |
||
196 | */ |
||
197 | View Code Duplication | public function cacheManager(array $curlOptions, $byteLimit) |
|
206 | |||
207 | /** |
||
208 | * Delay manager |
||
209 | * |
||
210 | * @return Client\Delay\ManagerInterface |
||
211 | * @throws DatabaseException |
||
212 | */ |
||
213 | public function delayManager() |
||
225 | } |
||
226 |
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.