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 declare(strict_types = 1); |
||
26 | class Client |
||
27 | { |
||
28 | /** |
||
29 | * @var string |
||
30 | */ |
||
31 | private $baseUrl = 'http://gateway.marvel.com/v1/public/'; |
||
32 | |||
33 | /** |
||
34 | * @var string |
||
35 | */ |
||
36 | private $publicApiKey; |
||
37 | |||
38 | /** |
||
39 | * @var string |
||
40 | */ |
||
41 | private $privateApiKey; |
||
42 | |||
43 | /** |
||
44 | * Client constructor. |
||
45 | * |
||
46 | * @param string $publicApiKey |
||
47 | * @param string $privateApiKey |
||
48 | */ |
||
49 | public function __construct(string $publicApiKey, string $privateApiKey) |
||
54 | |||
55 | /** |
||
56 | * Fetches lists of comic characters with optional filters. |
||
57 | * |
||
58 | * @param CharacterFilter|null $characterFilter |
||
59 | * |
||
60 | * @return CharacterDataWrapper |
||
61 | */ |
||
62 | public function getCharacters(CharacterFilter $characterFilter = null) : CharacterDataWrapper |
||
70 | |||
71 | /** |
||
72 | * This method fetches a single character resource. |
||
73 | * |
||
74 | * @param int $id |
||
75 | * |
||
76 | * @return CharacterDataWrapper |
||
77 | */ |
||
78 | View Code Duplication | public function getCharacter(int $id) : CharacterDataWrapper |
|
86 | |||
87 | /** |
||
88 | * Fetches lists of comics containing a specific character, with optional filters. |
||
89 | * |
||
90 | * @param int $id |
||
91 | * @param ComicFilter $comicFilter |
||
92 | * |
||
93 | * @return ComicDataWrapper |
||
94 | */ |
||
95 | View Code Duplication | public function getComicsForCharacter(int $id, ComicFilter $comicFilter = null) : ComicDataWrapper |
|
103 | |||
104 | /** |
||
105 | * Fetches lists of events in which a specific character appears, with optional filters. |
||
106 | * |
||
107 | * @param int $id |
||
108 | * @param EventFilter $eventFilter |
||
109 | * |
||
110 | * @return EventDataWrapper |
||
111 | */ |
||
112 | public function getEventsForCharacter(int $id, EventFilter $eventFilter = null) : EventDataWrapper |
||
120 | |||
121 | /** |
||
122 | * Fetches lists of comic series in which a specific character appears, with optional filters. |
||
123 | * |
||
124 | * @param int $id |
||
125 | * @param SeriesFilter $seriesFilter |
||
126 | * |
||
127 | * @return SeriesDataWrapper |
||
128 | */ |
||
129 | View Code Duplication | public function getSeriesForCharacter(int $id, SeriesFilter $seriesFilter = null) : SeriesDataWrapper |
|
137 | |||
138 | /** |
||
139 | * Fetches lists of comic stories featuring a specific character with optional filters. |
||
140 | * |
||
141 | * @param int $id |
||
142 | * @param StoryFilter $storyFilter |
||
143 | * |
||
144 | * @return StoryDataWrapper |
||
145 | */ |
||
146 | View Code Duplication | public function getStoriesForCharacter(int $id, StoryFilter $storyFilter = null) : StoryDataWrapper |
|
154 | |||
155 | /** |
||
156 | * Fetches lists of comics with optional filters. |
||
157 | * |
||
158 | * @param ComicFilter|null $comicFilter |
||
159 | * |
||
160 | * @return ComicDataWrapper |
||
161 | */ |
||
162 | View Code Duplication | public function getComics(ComicFilter $comicFilter = null) : ComicDataWrapper |
|
170 | |||
171 | /** |
||
172 | * This method fetches a single comic resource. |
||
173 | * |
||
174 | * @param int $id |
||
175 | * |
||
176 | * @return ComicDataWrapper |
||
177 | */ |
||
178 | View Code Duplication | public function getComic(int $id) : ComicDataWrapper |
|
186 | |||
187 | /** |
||
188 | * Fetches lists of characters which appear in a specific comic with optional filters. |
||
189 | * |
||
190 | * @param int $id |
||
191 | * @param CharacterFilter $characterFilter |
||
192 | * |
||
193 | * @return CharacterDataWrapper |
||
194 | */ |
||
195 | View Code Duplication | public function getCharactersForComic(int $id, CharacterFilter $characterFilter = null) : CharacterDataWrapper |
|
203 | |||
204 | /** |
||
205 | * Fetches lists of comic creators whose work appears in a specific comic, with optional filters. |
||
206 | * |
||
207 | * @param int $id |
||
208 | * @param CreatorFilter $creatorFilter |
||
209 | * |
||
210 | * @return CreatorDataWrapper |
||
211 | */ |
||
212 | View Code Duplication | public function getCreatorsForComics(int $id, CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
220 | |||
221 | /** |
||
222 | * Fetches lists of events in which a specific comic appears, with optional filters. |
||
223 | * |
||
224 | * @param int $id |
||
225 | * @param EventFilter $eventFilter |
||
226 | * |
||
227 | * @return EventDataWrapper |
||
228 | */ |
||
229 | public function getEventsForComics(int $id, EventFilter $eventFilter = null) : EventDataWrapper |
||
237 | |||
238 | /** |
||
239 | * Fetches lists of comic stories in a specific comic issue, with optional filters. |
||
240 | * |
||
241 | * @param int $id |
||
242 | * @param EventFilter $storyFilter |
||
243 | * |
||
244 | * @return StoryDataWrapper |
||
245 | */ |
||
246 | View Code Duplication | public function getStoriesForComics(int $id, EventFilter $storyFilter = null) : StoryDataWrapper |
|
254 | |||
255 | /** |
||
256 | * Fetches lists of events with optional filters. |
||
257 | * |
||
258 | * @param EventFilter|null $eventFilter |
||
259 | * |
||
260 | * @return EventDataWrapper |
||
261 | */ |
||
262 | public function getEvents(EventFilter $eventFilter = null) : EventDataWrapper |
||
270 | |||
271 | /** |
||
272 | * This method fetches a single event resource. |
||
273 | * |
||
274 | * @param int $id |
||
275 | * |
||
276 | * @return EventDataWrapper |
||
277 | */ |
||
278 | public function getEvent(int $id) : EventDataWrapper |
||
286 | |||
287 | /** |
||
288 | * Fetches lists of characters which appear in a specific event, with optional filters. |
||
289 | * |
||
290 | * @param int $id |
||
291 | * @param CharacterFilter $characterFilter |
||
292 | * |
||
293 | * @return CharacterDataWrapper |
||
294 | */ |
||
295 | View Code Duplication | public function getCharactersForEvent(int $id, CharacterFilter $characterFilter = null) : CharacterDataWrapper |
|
303 | |||
304 | /** |
||
305 | * Fetches lists of comics which take place during a specific event, with optional filters. |
||
306 | * |
||
307 | * @param int $id |
||
308 | * @param ComicFilter $comicFilter |
||
309 | * |
||
310 | * @return ComicDataWrapper |
||
311 | */ |
||
312 | View Code Duplication | public function getComicsForEvent(int $id, ComicFilter $comicFilter = null) : ComicDataWrapper |
|
320 | |||
321 | /** |
||
322 | * Fetches lists of comic creators whose work appears in a specific event, with optional filters. |
||
323 | * |
||
324 | * @param int $id |
||
325 | * @param CreatorFilter $creatorFilter |
||
326 | * |
||
327 | * @return CreatorDataWrapper |
||
328 | */ |
||
329 | View Code Duplication | public function getCreatorsForEvent(int $id, CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
337 | |||
338 | /** |
||
339 | * Fetches lists of comic series in which a specific event takes place, with optional filters. |
||
340 | * |
||
341 | * @param int $id |
||
342 | * @param SeriesFilter $seriesFilter |
||
343 | * |
||
344 | * @return SeriesDataWrapper |
||
345 | */ |
||
346 | View Code Duplication | public function getSeriesForEvent(int $id, SeriesFilter $seriesFilter = null) : SeriesDataWrapper |
|
354 | |||
355 | /** |
||
356 | * Fetches lists of comic stories from a specific event, with optional filters. |
||
357 | * |
||
358 | * @param int $id |
||
359 | * @param StoryFilter $storyFilter |
||
360 | * |
||
361 | * @return StoryDataWrapper |
||
362 | */ |
||
363 | View Code Duplication | public function getStoriesForEvent(int $id, StoryFilter $storyFilter = null) : StoryDataWrapper |
|
371 | |||
372 | /** |
||
373 | * Fetches lists of comic creators with optional filters. |
||
374 | * |
||
375 | * @param CreatorFilter|null $creatorFilter |
||
376 | * |
||
377 | * @return CreatorDataWrapper |
||
378 | */ |
||
379 | View Code Duplication | public function getCreators(CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
387 | |||
388 | /** |
||
389 | * This method fetches a single creator resource. |
||
390 | * |
||
391 | * @param int $id |
||
392 | * |
||
393 | * @return CreatorDataWrapper |
||
394 | */ |
||
395 | View Code Duplication | public function getCreator(int $id) : CreatorDataWrapper |
|
403 | |||
404 | /** |
||
405 | * Fetches lists of events featuring the work of a specific creator with optional filters. |
||
406 | * |
||
407 | * @param int $id |
||
408 | * @param CreatorFilter $creatorFilter |
||
409 | * |
||
410 | * @return CreatorDataWrapper |
||
411 | */ |
||
412 | View Code Duplication | public function getComicsForCreator(int $id, CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
420 | |||
421 | /** |
||
422 | * Fetches lists of comic series in which a specific creator's work appears, with optional filters. |
||
423 | * |
||
424 | * @param int $id |
||
425 | * @param SeriesFilter $seriesFilter |
||
426 | * |
||
427 | * @return SeriesDataWrapper |
||
428 | */ |
||
429 | View Code Duplication | public function getSeriesForCreator(int $id, SeriesFilter $seriesFilter = null) : SeriesDataWrapper |
|
437 | |||
438 | /** |
||
439 | * Fetches lists of comic stories by a specific creator with optional filters. |
||
440 | * |
||
441 | * @param int $id |
||
442 | * @param StoryFilter $storyFilter |
||
443 | * |
||
444 | * @return StoryDataWrapper |
||
445 | */ |
||
446 | View Code Duplication | public function getStoriesForCreator(int $id, StoryFilter $storyFilter = null) : StoryDataWrapper |
|
454 | |||
455 | /** |
||
456 | * Fetches lists of comic series with optional filters. |
||
457 | * |
||
458 | * @param SeriesFilter|null $seriesFilter |
||
459 | * |
||
460 | * @return SeriesDataWrapper |
||
461 | */ |
||
462 | View Code Duplication | public function getSeries(SeriesFilter $seriesFilter = null) : SeriesDataWrapper |
|
470 | |||
471 | /** |
||
472 | * This method fetches a single comic series resource. |
||
473 | * |
||
474 | * @param int $id |
||
475 | * |
||
476 | * @return SeriesDataWrapper |
||
477 | */ |
||
478 | View Code Duplication | public function getASeries(int $id) : SeriesDataWrapper |
|
486 | |||
487 | /** |
||
488 | * Fetches lists of characters which appear in specific series, with optional filters. |
||
489 | * |
||
490 | * @param int $id |
||
491 | * @param CharacterFilter $characterFilter |
||
492 | * |
||
493 | * @return CharacterDataWrapper |
||
494 | */ |
||
495 | View Code Duplication | public function getCharactersForSeries(int $id, CharacterFilter $characterFilter = null) : CharacterDataWrapper |
|
503 | |||
504 | /** |
||
505 | * Fetches lists of comics which are published as part of a specific series, with optional filters. |
||
506 | * |
||
507 | * @param int $id |
||
508 | * @param ComicFilter $comicFilter |
||
509 | * |
||
510 | * @return ComicDataWrapper |
||
511 | */ |
||
512 | View Code Duplication | public function getComicsForSeries(int $id, ComicFilter $comicFilter = null) : ComicDataWrapper |
|
520 | |||
521 | /** |
||
522 | * Fetches lists of comic creators whose work appears in a specific series, with optional filters. |
||
523 | * |
||
524 | * @param int $id |
||
525 | * @param CreatorFilter $creatorFilter |
||
526 | * |
||
527 | * @return CreatorDataWrapper |
||
528 | */ |
||
529 | View Code Duplication | public function getCreatorsForSeries(int $id, CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
537 | |||
538 | /** |
||
539 | * Fetches lists of events which occur in a specific series, with optional filters. |
||
540 | * |
||
541 | * @param int $id |
||
542 | * @param EventFilter $eventFilter |
||
543 | * |
||
544 | * @return EventDataWrapper |
||
545 | */ |
||
546 | public function getEventsForSeries(int $id, EventFilter $eventFilter = null) : EventDataWrapper |
||
554 | |||
555 | /** |
||
556 | * Fetches lists of comic stories from a specific series with optional filters. |
||
557 | * |
||
558 | * @param int $id |
||
559 | * @param StoryFilter $storyFilter |
||
560 | * |
||
561 | * @return StoryDataWrapper |
||
562 | */ |
||
563 | View Code Duplication | public function getStoriesForSeries(int $id, StoryFilter $storyFilter = null) : StoryDataWrapper |
|
571 | |||
572 | /** |
||
573 | * Fetches lists of comic stories with optional filters. |
||
574 | * |
||
575 | * @param StoryFilter|null $storyFilter |
||
576 | * |
||
577 | * @return StoryDataWrapper |
||
578 | */ |
||
579 | View Code Duplication | public function getStories(StoryFilter $storyFilter = null) : StoryDataWrapper |
|
587 | |||
588 | /** |
||
589 | * This method fetches a single comic story resource. |
||
590 | * |
||
591 | * @param int $id |
||
592 | * |
||
593 | * @return StoryDataWrapper |
||
594 | */ |
||
595 | View Code Duplication | public function getStory(int $id) : StoryDataWrapper |
|
603 | |||
604 | /** |
||
605 | * Fetches lists of comic characters appearing in a single story, with optional filters. |
||
606 | * |
||
607 | * @param int $id |
||
608 | * @param CharacterFilter $characterFilter |
||
609 | * |
||
610 | * @return CharacterDataWrapper |
||
611 | */ |
||
612 | View Code Duplication | public function getCharactersForStory(int $id, CharacterFilter $characterFilter = null) : CharacterDataWrapper |
|
620 | |||
621 | /** |
||
622 | * Fetches lists of comics in which a specific story appears, with optional filters. |
||
623 | * |
||
624 | * @param int $id |
||
625 | * @param ComicFilter $comicFilter |
||
626 | * |
||
627 | * @return ComicDataWrapper |
||
628 | */ |
||
629 | View Code Duplication | public function getComicsForStory(int $id, ComicFilter $comicFilter = null) : ComicDataWrapper |
|
637 | |||
638 | /** |
||
639 | * Fetches lists of comic creators whose work appears in a specific story, with optional filters. |
||
640 | * |
||
641 | * @param int $id |
||
642 | * @param CreatorFilter $creatorFilter |
||
643 | * |
||
644 | * @return CreatorDataWrapper |
||
645 | */ |
||
646 | View Code Duplication | public function getCreatorsForStory(int $id, CreatorFilter $creatorFilter = null) : CreatorDataWrapper |
|
654 | |||
655 | /** |
||
656 | * Fetches lists of events in which a specific story appears, with optional filters. |
||
657 | * |
||
658 | * @param int $id |
||
659 | * @param EventFilter $eventFilter |
||
660 | * |
||
661 | * @return EventDataWrapper |
||
662 | */ |
||
663 | public function getEventsForStory(int $id, EventFilter $eventFilter = null) : EventDataWrapper |
||
671 | |||
672 | /** |
||
673 | * Fetches lists of comic series in which the specified story takes place. |
||
674 | * |
||
675 | * @param int $id |
||
676 | * @param SeriesFilter $seriesFilter |
||
677 | * |
||
678 | * @return SeriesDataWrapper |
||
679 | */ |
||
680 | View Code Duplication | public function getSeriesForStory(int $id, SeriesFilter $seriesFilter = null) : SeriesDataWrapper |
|
688 | |||
689 | /** |
||
690 | * @param string $operation |
||
691 | * @param object|null $query |
||
692 | * |
||
693 | * @return Response |
||
694 | */ |
||
695 | private function call(string $operation, $query = null) : Response |
||
706 | |||
707 | /** |
||
708 | * @param string $url |
||
709 | * @param array $params |
||
710 | * |
||
711 | * @return Response |
||
712 | */ |
||
713 | private function send(string $url, array $params = array()) : Response |
||
733 | |||
734 | /** |
||
735 | * @param Response $response |
||
736 | * @param string $dataWrapper |
||
737 | * |
||
738 | * @return Object |
||
739 | */ |
||
740 | private function formatResponse(Response $response, string $dataWrapper) |
||
748 | } |
||
749 |
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.