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 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 |
||
15 | class Client |
||
16 | { |
||
17 | /** |
||
18 | * RegExp for bot commands |
||
19 | */ |
||
20 | const REGEXP = '/^(?:@\w+\s)?\/([^\s@]+)(@\S+)?\s?(.*)$/'; |
||
21 | |||
22 | /** |
||
23 | * @var BotApi |
||
24 | */ |
||
25 | protected $api; |
||
26 | |||
27 | /** |
||
28 | * @var EventCollection |
||
29 | */ |
||
30 | protected $events; |
||
31 | |||
32 | /** |
||
33 | * Client constructor |
||
34 | * |
||
35 | * @param string $token Telegram Bot API token |
||
36 | * @param string|null $trackerToken Yandex AppMetrica application api_key |
||
37 | */ |
||
38 | 7 | public function __construct($token, $trackerToken = null) |
|
43 | |||
44 | /** |
||
45 | * @param $name |
||
46 | * @param array $arguments |
||
47 | * @return mixed |
||
48 | * @throws BadMethodCallException |
||
49 | */ |
||
50 | 1 | public function __call($name, array $arguments) |
|
60 | |||
61 | /** |
||
62 | * Use this method to add an event. |
||
63 | * If second closure will return true (or if you are passed null instead of closure), first one will be executed. |
||
64 | * |
||
65 | * @param Closure $event |
||
66 | * @param Closure|null $checker |
||
67 | * @return Client |
||
68 | */ |
||
69 | 1 | public function on(Closure $event, Closure $checker = null) |
|
75 | |||
76 | /** |
||
77 | * Handle updates |
||
78 | * |
||
79 | * @param Update[] $updates |
||
80 | */ |
||
81 | 4 | public function handle(array $updates) |
|
88 | |||
89 | /** |
||
90 | * Webhook handler |
||
91 | * |
||
92 | * @return void |
||
93 | * @throws InvalidJsonException |
||
94 | */ |
||
95 | public function run() |
||
101 | |||
102 | /** |
||
103 | * @return false|string |
||
104 | */ |
||
105 | public function getRawBody() |
||
109 | |||
110 | /** |
||
111 | * @param Closure $action |
||
112 | * @return $this |
||
113 | */ |
||
114 | public function anyUpdate(Closure $action) |
||
128 | |||
129 | /** |
||
130 | * Use this method to add command. Parameters will be automatically parsed and passed to closure. |
||
131 | * |
||
132 | * @param string $name |
||
133 | * @param Closure $action |
||
134 | * @return Client |
||
135 | */ |
||
136 | public function command($name, Closure $action) |
||
140 | |||
141 | public function message(Closure $action) |
||
145 | |||
146 | public function editedMessage(Closure $action) |
||
150 | |||
151 | public function callbackQuery(Closure $action) |
||
155 | |||
156 | public function channelPost(Closure $action) |
||
160 | |||
161 | public function editedChannelPost(Closure $action) |
||
165 | |||
166 | public function inlineQuery(Closure $action) |
||
170 | |||
171 | public function chosenInlineResult(Closure $action) |
||
175 | |||
176 | public function shippingQuery(Closure $action) |
||
180 | |||
181 | public function preCheckoutQuery(Closure $action) |
||
185 | |||
186 | /** |
||
187 | * Returns event function to handling the command. |
||
188 | * |
||
189 | * @param Closure $action |
||
190 | * @return Closure |
||
191 | */ |
||
192 | protected static function getCommandEvent(Closure $action) |
||
220 | |||
221 | View Code Duplication | protected static function getMessageEvent(Closure $action) |
|
233 | |||
234 | View Code Duplication | protected static function getEditedMessageEvent(Closure $action) |
|
246 | |||
247 | View Code Duplication | protected static function getChannelPostEvent(Closure $action) |
|
259 | |||
260 | View Code Duplication | protected static function getCallbackQueryEvent(Closure $action) |
|
272 | |||
273 | View Code Duplication | protected static function getEditedChannelPostEvent(Closure $action) |
|
285 | |||
286 | 4 | View Code Duplication | protected static function getInlineQueryEvent(Closure $action) |
298 | |||
299 | View Code Duplication | protected static function getChosenInlineResultEvent(Closure $action) |
|
311 | |||
312 | View Code Duplication | protected static function getShippingQueryEvent(Closure $action) |
|
324 | |||
325 | View Code Duplication | protected static function getPreCheckoutQueryEvent(Closure $action) |
|
337 | |||
338 | /** |
||
339 | * Returns check function to handling the command. |
||
340 | * |
||
341 | * @param string $name |
||
342 | * @return Closure |
||
343 | */ |
||
344 | protected static function getCommandChecker($name) |
||
357 | |||
358 | /** |
||
359 | * Returns check function to handling the message. |
||
360 | * |
||
361 | * @return Closure |
||
362 | */ |
||
363 | protected static function getMessageChecker() |
||
369 | |||
370 | /** |
||
371 | * Returns check function to handling the edited message. |
||
372 | * |
||
373 | * @return Closure |
||
374 | */ |
||
375 | protected static function getEditedMessageChecker() |
||
381 | |||
382 | /** |
||
383 | * Returns check function to handling the channel post. |
||
384 | * |
||
385 | * @return Closure |
||
386 | */ |
||
387 | protected static function getChannelPostChecker() |
||
393 | |||
394 | /** |
||
395 | * Returns check function to handling the callbackQuery. |
||
396 | * |
||
397 | * @return Closure |
||
398 | */ |
||
399 | protected static function getCallbackQueryChecker() |
||
405 | |||
406 | /** |
||
407 | * Returns check function to handling the edited channel post. |
||
408 | * |
||
409 | * @return Closure |
||
410 | */ |
||
411 | protected static function getEditedChannelPostChecker() |
||
417 | |||
418 | /** |
||
419 | * Returns check function to handling the chosen inline result. |
||
420 | * |
||
421 | * @return Closure |
||
422 | */ |
||
423 | protected static function getChosenInlineResultChecker() |
||
429 | |||
430 | /** |
||
431 | * Returns check function to handling the inline queries. |
||
432 | * |
||
433 | * @return Closure |
||
434 | */ |
||
435 | 4 | protected static function getInlineQueryChecker() |
|
441 | |||
442 | /** |
||
443 | * Returns check function to handling the shipping queries. |
||
444 | * |
||
445 | * @return Closure |
||
446 | */ |
||
447 | protected static function getShippingQueryChecker() |
||
453 | |||
454 | /** |
||
455 | * Returns check function to handling the pre checkout queries. |
||
456 | * |
||
457 | * @return Closure |
||
458 | */ |
||
459 | protected static function getPreCheckoutQueryChecker() |
||
465 | } |
||
466 |