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 Connection 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 Connection, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class Connection extends ClientConnection |
||
10 | { |
||
11 | |||
12 | /** |
||
13 | * @var integer Sequence. Pointer of packet sequence |
||
14 | */ |
||
15 | public $seq = 0; |
||
16 | |||
17 | /** |
||
18 | * @var integer Client flags |
||
19 | */ |
||
20 | public $clientFlags = 239237; |
||
21 | |||
22 | /** |
||
23 | * @var integer |
||
24 | */ |
||
25 | public $threadId; |
||
26 | |||
27 | /** |
||
28 | * @var string |
||
29 | */ |
||
30 | public $scramble; |
||
31 | |||
32 | /** |
||
33 | * @var string |
||
34 | */ |
||
35 | public $serverver; |
||
36 | |||
37 | /** |
||
38 | * @var integer |
||
39 | */ |
||
40 | public $serverCaps; |
||
41 | |||
42 | /** |
||
43 | * @var integer |
||
44 | */ |
||
45 | public $serverLang; |
||
46 | |||
47 | /** |
||
48 | * @var integer Server flags: http://dev.mysql.com/doc/internals/en/status-flags.html |
||
49 | */ |
||
50 | public $serverStatus; |
||
51 | |||
52 | /** |
||
53 | * @var integer Number of warnings generated by the command |
||
54 | */ |
||
55 | public $warnCount; |
||
56 | |||
57 | /** |
||
58 | * @var string |
||
59 | */ |
||
60 | public $message; |
||
61 | |||
62 | /** |
||
63 | * @var integer Charset number (see MySQL charset list) |
||
64 | */ |
||
65 | public $charsetNumber = 0x21; |
||
66 | |||
67 | /** |
||
68 | * @var string User name |
||
69 | */ |
||
70 | protected $user = 'root'; |
||
71 | |||
72 | /** |
||
73 | * @var string Password |
||
74 | */ |
||
75 | protected $password = ''; |
||
76 | |||
77 | /** |
||
78 | * @var string Database name |
||
79 | */ |
||
80 | public $dbname = ''; |
||
81 | |||
82 | /** |
||
83 | * @TODO DESCR |
||
84 | */ |
||
85 | const STATE_STANDBY = 0; |
||
86 | |||
87 | /** |
||
88 | * @TODO DESCR |
||
89 | */ |
||
90 | const STATE_BODY = 1; |
||
91 | |||
92 | /** |
||
93 | * @var string Phase |
||
94 | */ |
||
95 | protected $phase = 0; |
||
96 | |||
97 | /** |
||
98 | * @TODO DESCR |
||
99 | */ |
||
100 | const PHASE_GOT_INIT = 1; |
||
101 | |||
102 | /** |
||
103 | * @TODO DESCR |
||
104 | */ |
||
105 | const PHASE_AUTH_SENT = 2; |
||
106 | |||
107 | /** |
||
108 | * @TODO DESCR |
||
109 | */ |
||
110 | const PHASE_AUTH_ERR = 3; |
||
111 | |||
112 | /** |
||
113 | * @TODO DESCR |
||
114 | */ |
||
115 | const PHASE_HANDSHAKED = 4; |
||
116 | |||
117 | /** |
||
118 | * @var integer State of pointer of incoming data. 0 - Result Set Header Packet, 1 - Field Packet, 2 - Row Packet |
||
119 | */ |
||
120 | protected $rsState = 0; |
||
121 | |||
122 | /** |
||
123 | * @TODO DESCR |
||
124 | */ |
||
125 | const RS_STATE_HEADER = 0; |
||
126 | |||
127 | /** |
||
128 | * @TODO DESCR |
||
129 | */ |
||
130 | const RS_STATE_FIELD = 1; |
||
131 | |||
132 | /** |
||
133 | * @TODO DESCR |
||
134 | */ |
||
135 | const RS_STATE_ROW = 2; |
||
136 | |||
137 | /** |
||
138 | * @var integer Packet size |
||
139 | */ |
||
140 | protected $pctSize = 0; |
||
141 | |||
142 | /** |
||
143 | * @var array Result rows |
||
144 | */ |
||
145 | public $resultRows = []; |
||
146 | |||
147 | /** |
||
148 | * @var array Result fields |
||
149 | */ |
||
150 | public $resultFields = []; |
||
151 | |||
152 | /** |
||
153 | * @var object Property holds a reference to user's object |
||
154 | */ |
||
155 | public $context; |
||
156 | |||
157 | /** |
||
158 | * @var integer INSERT_ID() |
||
159 | */ |
||
160 | public $insertId; |
||
161 | |||
162 | /** |
||
163 | * @var integer Affected rows |
||
164 | */ |
||
165 | public $affectedRows; |
||
166 | |||
167 | /** |
||
168 | * @var integer Protocol version |
||
169 | */ |
||
170 | public $protover = 0; |
||
171 | |||
172 | /** |
||
173 | * @var integer Timeout |
||
174 | */ |
||
175 | public $timeout = 120; |
||
176 | |||
177 | /** |
||
178 | * @var integer Error number |
||
179 | */ |
||
180 | public $errno = 0; |
||
181 | |||
182 | /** |
||
183 | * @var string Error message |
||
184 | */ |
||
185 | public $errmsg = ''; |
||
186 | |||
187 | /** |
||
188 | * @var integer Low mark |
||
189 | */ |
||
190 | protected $lowMark = 4; |
||
191 | |||
192 | /** |
||
193 | * Executes the given callback when/if the connection is handshaked |
||
194 | * @param callable $cb Callback |
||
195 | * @callback $cb ( Connection $conn, boolean $success ) |
||
196 | * @return void |
||
197 | */ |
||
198 | View Code Duplication | public function onConnected($cb) |
|
211 | |||
212 | /** |
||
213 | * Called when the connection is handshaked (at low-level), and peer is ready to recv. data |
||
214 | * @return void |
||
215 | */ |
||
216 | public function onReady() |
||
222 | |||
223 | /** |
||
224 | * Sends a packet |
||
225 | * @param string $packet Data |
||
226 | * @return boolean Success |
||
227 | */ |
||
228 | public function sendPacket($packet) |
||
233 | |||
234 | /** |
||
235 | * Builds length-encoded binary string |
||
236 | * @param string $s String |
||
237 | * @return string Resulting binary string |
||
238 | */ |
||
239 | public function buildLenEncodedBinary($s) |
||
261 | |||
262 | /** |
||
263 | * Parses length-encoded binary integer |
||
264 | * @return integer Result |
||
265 | */ |
||
266 | public function parseEncodedBinary() |
||
286 | |||
287 | /** |
||
288 | * Parse length-encoded string |
||
289 | * @return integer Result |
||
290 | */ |
||
291 | public function parseEncodedString() |
||
299 | |||
300 | /** |
||
301 | * Generates auth. token |
||
302 | * @param string $scramble Scramble string |
||
303 | * @param string $password Password |
||
304 | * @return string Result |
||
305 | */ |
||
306 | public function getAuthToken($scramble, $password) |
||
310 | |||
311 | /** |
||
312 | * Sends auth. packet |
||
313 | * @return void |
||
314 | */ |
||
315 | public function auth() |
||
349 | |||
350 | /** |
||
351 | * Sends SQL-query |
||
352 | * @param string $q Query |
||
353 | * @param callable $cb Optional. Callback called when response received |
||
354 | * @callback $cb ( Connection $conn, boolean $success ) |
||
355 | * @return boolean Success |
||
356 | */ |
||
357 | public function query($q, $cb = null) |
||
364 | |||
365 | /** |
||
366 | * Begins a transaction |
||
367 | * @param callable $cb Optional. Callback called when response received |
||
368 | * @throws ConnectionFinished |
||
369 | */ |
||
370 | public function begin($cb = null) |
||
375 | |||
376 | /** |
||
377 | * Commit a transaction |
||
378 | * @param callable $cb Optional. Callback called when response received |
||
379 | * @throws ConnectionFinished |
||
380 | */ |
||
381 | public function commit($cb = null) |
||
386 | |||
387 | /** |
||
388 | * Rollback a transaction |
||
389 | * @throws ConnectionFinished |
||
390 | */ |
||
391 | public function rollback($cb = null) |
||
396 | |||
397 | /** |
||
398 | * Sends echo-request |
||
399 | * @param callable $cb Optional. Callback called when response received |
||
400 | * @callback $cb ( Connection $conn, boolean $success ) |
||
401 | * @return boolean Success |
||
402 | */ |
||
403 | public function ping($cb = null) |
||
407 | |||
408 | /** |
||
409 | * Sends arbitrary command |
||
410 | * @param string $cmd Command |
||
411 | * @param string $q Data |
||
412 | * @param callable $cb Optional |
||
413 | * @throws ConnectionFinished |
||
414 | * @callback $cb ( Connection $conn, boolean $success ) |
||
415 | * @return boolean Success |
||
416 | */ |
||
417 | View Code Duplication | public function command($cmd, $q = '', $cb = null) |
|
418 | { |
||
419 | if ($this->phase !== self::PHASE_HANDSHAKED) { |
||
420 | return false; |
||
421 | } |
||
422 | |||
423 | $this->onResponse->push($cb); |
||
424 | $this->seq = 0; |
||
425 | $this->sendPacket(chr($cmd) . $q); |
||
426 | |||
427 | return true; |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * Sets default database name |
||
432 | * @param string $name Database name |
||
433 | * @return boolean Success |
||
434 | */ |
||
435 | public function selectDB($name) |
||
445 | |||
446 | /** |
||
447 | * Called when new data received |
||
448 | * @return void |
||
449 | */ |
||
450 | public function onRead() |
||
598 | |||
599 | /** |
||
600 | * Called when connection finishes |
||
601 | * @return void |
||
602 | */ |
||
603 | public function onFinish() |
||
608 | |||
609 | /** |
||
610 | * Called when the whole result received |
||
611 | * @return void |
||
612 | */ |
||
613 | public function onResultDone() |
||
621 | |||
622 | /** |
||
623 | * Called when error occured |
||
624 | * @return void |
||
625 | */ |
||
626 | public function onError() |
||
642 | } |
||
643 |
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.