Complex classes like Client 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 Client, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class Client implements Interfaces\ClientInterface |
||
29 | { |
||
30 | use SocketTrait, ShortsTrait; |
||
31 | |||
32 | /** |
||
33 | * Configuration of connection |
||
34 | * |
||
35 | * @var \RouterOS\Config |
||
36 | */ |
||
37 | private $config; |
||
38 | |||
39 | /** |
||
40 | * API communication object |
||
41 | * |
||
42 | * @var \RouterOS\APIConnector |
||
43 | */ |
||
44 | private $connector; |
||
45 | |||
46 | /** |
||
47 | * Some strings with custom output |
||
48 | * |
||
49 | * @var string |
||
50 | */ |
||
51 | private $customOutput; |
||
52 | |||
53 | /** |
||
54 | * Client constructor. |
||
55 | * |
||
56 | * @param array|\RouterOS\Interfaces\ConfigInterface $config Array with configuration or Config object |
||
57 | * @param bool $autoConnect If false it will skip auto-connect stage if not need to instantiate connection |
||
58 | * |
||
59 | * @throws \RouterOS\Exceptions\ClientException |
||
60 | * @throws \RouterOS\Exceptions\ConfigException |
||
61 | * @throws \RouterOS\Exceptions\QueryException |
||
62 | */ |
||
63 | 9 | public function __construct($config, bool $autoConnect = true) |
|
88 | |||
89 | /** |
||
90 | * Get some parameter from config |
||
91 | * |
||
92 | * @param string $parameter Name of required parameter |
||
93 | * |
||
94 | * @return mixed |
||
95 | * @throws \RouterOS\Exceptions\ConfigException |
||
96 | */ |
||
97 | 8 | private function config(string $parameter) |
|
101 | |||
102 | /** |
||
103 | * Send write query to RouterOS (modern version of write) |
||
104 | * |
||
105 | * @param array|string|\RouterOS\Interfaces\QueryInterface $endpoint Path of API query or Query object |
||
106 | * @param array|null $where List of where filters |
||
107 | * @param string|null $operations Some operations which need make on response |
||
108 | * @param string|null $tag Mark query with tag |
||
109 | * |
||
110 | * @return \RouterOS\Interfaces\ClientInterface |
||
111 | * @throws \RouterOS\Exceptions\QueryException |
||
112 | * @throws \RouterOS\Exceptions\ClientException |
||
113 | * @throws \RouterOS\Exceptions\ConfigException |
||
114 | * @since 1.0.0 |
||
115 | */ |
||
116 | 7 | public function query($endpoint, array $where = null, string $operations = null, string $tag = null): ClientInterface |
|
150 | |||
151 | /** |
||
152 | * Query helper |
||
153 | * |
||
154 | * @param array $item |
||
155 | * @param \RouterOS\Interfaces\QueryInterface $query |
||
156 | * |
||
157 | * @return \RouterOS\Query |
||
158 | * @throws \RouterOS\Exceptions\QueryException |
||
159 | * @throws \RouterOS\Exceptions\ClientException |
||
160 | */ |
||
161 | 1 | private function preQuery(array $item, QueryInterface $query): QueryInterface |
|
185 | |||
186 | /** |
||
187 | * Send write query object to RouterOS |
||
188 | * |
||
189 | * @param \RouterOS\Interfaces\QueryInterface $query |
||
190 | * |
||
191 | * @return \RouterOS\Interfaces\ClientInterface |
||
192 | * @throws \RouterOS\Exceptions\QueryException |
||
193 | * @throws \RouterOS\Exceptions\ConfigException |
||
194 | * @since 1.0.0 |
||
195 | */ |
||
196 | 7 | private function writeRAW(QueryInterface $query): ClientInterface |
|
226 | |||
227 | /** |
||
228 | * Read RAW response from RouterOS, it can be /export command results also, not only array from API |
||
229 | * |
||
230 | * @return array|string |
||
231 | * @since 1.0.0 |
||
232 | */ |
||
233 | 7 | private function readRAW() |
|
275 | |||
276 | /** |
||
277 | * Read answer from server after query was executed |
||
278 | * |
||
279 | * A Mikrotik reply is formed of blocks |
||
280 | * Each block starts with a word, one of ('!re', '!trap', '!done', '!fatal') |
||
281 | * Each block end with an zero byte (empty line) |
||
282 | * Reply ends with a complete !done or !fatal block (ended with 'empty line') |
||
283 | * A !fatal block precedes TCP connexion close |
||
284 | * |
||
285 | * @param bool $parse If need parse output to array |
||
286 | * |
||
287 | * @return mixed |
||
288 | */ |
||
289 | 7 | public function read(bool $parse = true) |
|
303 | |||
304 | /** |
||
305 | * Read using Iterators to improve performance on large dataset |
||
306 | * |
||
307 | * @return \RouterOS\ResponseIterator |
||
308 | * @since 1.0.0 |
||
309 | */ |
||
310 | public function readAsIterator(): ResponseIterator |
||
314 | |||
315 | /** |
||
316 | * This method was created by memory save reasons, it convert response |
||
317 | * from RouterOS to readable array in safe way. |
||
318 | * |
||
319 | * @param array $raw Array RAW response from server |
||
320 | * |
||
321 | * @return mixed |
||
322 | * |
||
323 | * Based on RouterOSResponseArray solution by @arily |
||
324 | * |
||
325 | * @link https://github.com/arily/RouterOSResponseArray |
||
326 | * @since 1.0.0 |
||
327 | */ |
||
328 | 3 | private function rosario(array $raw): array |
|
359 | |||
360 | /** |
||
361 | * Parse response from Router OS |
||
362 | * |
||
363 | * @param array $response Response data |
||
364 | * |
||
365 | * @return array Array with parsed data |
||
366 | */ |
||
367 | 3 | public function parseResponse(array $response): array |
|
397 | |||
398 | /** |
||
399 | * Response helper |
||
400 | * |
||
401 | * @param string $value Value which should be parsed |
||
402 | * @param array $result Array with parsed response |
||
403 | * @param null|array $matches Matched words |
||
404 | * @param string|int $iterator Type of iterations or number of item |
||
405 | */ |
||
406 | 3 | private function preParseResponse(string $value, array &$result, ?array &$matches, $iterator = 'after'): void |
|
413 | |||
414 | /** |
||
415 | * Parse result from RouterOS by regular expression |
||
416 | * |
||
417 | * @param string $value |
||
418 | * @param null|array $matches |
||
419 | */ |
||
420 | 3 | private function pregResponse(string $value, ?array &$matches): void |
|
424 | |||
425 | /** |
||
426 | * Authorization logic |
||
427 | * |
||
428 | * @param bool $legacyRetry Retry login if we detect legacy version of RouterOS |
||
429 | * |
||
430 | * @return bool |
||
431 | * @throws \RouterOS\Exceptions\ClientException |
||
432 | * @throws \RouterOS\Exceptions\ConfigException |
||
433 | * @throws \RouterOS\Exceptions\QueryException |
||
434 | */ |
||
435 | 7 | private function login(bool $legacyRetry = false): bool |
|
480 | |||
481 | /** |
||
482 | * Detect by login request if firmware is legacy |
||
483 | * |
||
484 | * @param array $response |
||
485 | * |
||
486 | * @return bool |
||
487 | * @throws \RouterOS\Exceptions\ConfigException |
||
488 | */ |
||
489 | 6 | private function isLegacy(array $response): bool |
|
493 | |||
494 | /** |
||
495 | * Connect to socket server |
||
496 | * |
||
497 | * @return bool |
||
498 | * @throws \RouterOS\Exceptions\ClientException |
||
499 | * @throws \RouterOS\Exceptions\ConfigException |
||
500 | * @throws \RouterOS\Exceptions\QueryException |
||
501 | */ |
||
502 | 8 | public function connect(): bool |
|
533 | |||
534 | /** |
||
535 | * Check if custom output is not empty |
||
536 | * |
||
537 | * @return bool |
||
538 | */ |
||
539 | 7 | private function isCustomOutput(): bool |
|
543 | |||
544 | /** |
||
545 | * Execute export command on remote host, it also will be used |
||
546 | * if "/export" command passed to query. |
||
547 | * |
||
548 | * @param string|null $arguments String with arguments which should be passed to export command |
||
549 | * |
||
550 | * @return string |
||
551 | * @throws \RouterOS\Exceptions\ConfigException |
||
552 | * @since 1.3.0 |
||
553 | */ |
||
554 | public function export(string $arguments = null): string |
||
572 | } |
||
573 |
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.