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 Encoder 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 Encoder, and based on these observations, apply Extract Interface, too.
1 | <?php declare(strict_types=1); |
||
39 | class Encoder implements EncoderInterface |
||
40 | { |
||
41 | /** |
||
42 | * Default value. |
||
43 | */ |
||
44 | const DEFAULT_URL_PREFIX = ''; |
||
45 | |||
46 | /** |
||
47 | * Default value. |
||
48 | */ |
||
49 | const DEFAULT_INCLUDE_PATHS = []; |
||
50 | |||
51 | /** |
||
52 | * Default value. |
||
53 | */ |
||
54 | const DEFAULT_FIELD_SET_FILTERS = []; |
||
55 | |||
56 | /** |
||
57 | * Default encode options. |
||
58 | * |
||
59 | * @link http://php.net/manual/en/function.json-encode.php |
||
60 | */ |
||
61 | const DEFAULT_JSON_ENCODE_OPTIONS = 0; |
||
62 | |||
63 | /** |
||
64 | * Default encode depth. |
||
65 | * |
||
66 | * @link http://php.net/manual/en/function.json-encode.php |
||
67 | */ |
||
68 | const DEFAULT_JSON_ENCODE_DEPTH = 512; |
||
69 | |||
70 | /** |
||
71 | * @var SchemaContainerInterface |
||
72 | */ |
||
73 | private $container; |
||
74 | |||
75 | /** |
||
76 | * @var FactoryInterface |
||
77 | */ |
||
78 | private $factory; |
||
79 | |||
80 | /** |
||
81 | * @var string |
||
82 | */ |
||
83 | private $urlPrefix; |
||
84 | |||
85 | /** |
||
86 | * @var array |
||
87 | */ |
||
88 | private $includePaths; |
||
89 | |||
90 | /** |
||
91 | * @var array |
||
92 | */ |
||
93 | private $fieldSets; |
||
94 | |||
95 | /** |
||
96 | * @var int |
||
97 | */ |
||
98 | private $encodeOptions; |
||
99 | |||
100 | /** |
||
101 | * @var int |
||
102 | */ |
||
103 | private $encodeDepth; |
||
104 | |||
105 | /** |
||
106 | * @var iterable |
||
107 | */ |
||
108 | private $links; |
||
109 | |||
110 | /** |
||
111 | * @var iterable |
||
112 | */ |
||
113 | private $profile; |
||
114 | |||
115 | /** |
||
116 | * @var bool |
||
117 | */ |
||
118 | private $hasMeta; |
||
119 | |||
120 | /** |
||
121 | * @var mixed |
||
122 | */ |
||
123 | private $meta; |
||
124 | |||
125 | /** |
||
126 | * @var string|null |
||
127 | */ |
||
128 | private $jsonApiVersion; |
||
129 | |||
130 | /** |
||
131 | * @var mixed |
||
132 | */ |
||
133 | private $jsonApiMeta; |
||
134 | |||
135 | /** |
||
136 | * @var bool |
||
137 | */ |
||
138 | private $hasJsonApiMeta; |
||
139 | |||
140 | /** |
||
141 | * @param FactoryInterface $factory |
||
142 | * @param SchemaContainerInterface $container |
||
143 | */ |
||
144 | 78 | public function __construct( |
|
153 | |||
154 | /** |
||
155 | * Create encoder instance. |
||
156 | * |
||
157 | * @param array $schemas Schema providers. |
||
158 | * |
||
159 | * @return EncoderInterface |
||
160 | */ |
||
161 | 78 | public static function instance(array $schemas = []): EncoderInterface |
|
169 | |||
170 | /** |
||
171 | * @inheritdoc |
||
172 | */ |
||
173 | 78 | public function withUrlPrefix(string $prefix): EncoderInterface |
|
179 | |||
180 | /** |
||
181 | * @inheritdoc |
||
182 | */ |
||
183 | 78 | public function withIncludedPaths(iterable $paths): EncoderInterface |
|
203 | |||
204 | /** |
||
205 | * @inheritdoc |
||
206 | */ |
||
207 | 78 | public function withFieldSets(array $fieldSets): EncoderInterface |
|
213 | |||
214 | /** |
||
215 | * @inheritdoc |
||
216 | */ |
||
217 | 78 | public function withEncodeOptions(int $options): EncoderInterface |
|
223 | |||
224 | /** |
||
225 | * @inheritdoc |
||
226 | */ |
||
227 | 78 | public function withEncodeDepth(int $depth): EncoderInterface |
|
235 | |||
236 | /** |
||
237 | * @inheritdoc |
||
238 | */ |
||
239 | 5 | public function withLinks(iterable $links): EncoderInterface |
|
245 | |||
246 | /** |
||
247 | * @inheritdoc |
||
248 | */ |
||
249 | 1 | public function withProfile(iterable $links): EncoderInterface |
|
255 | |||
256 | /** |
||
257 | * @inheritdoc |
||
258 | */ |
||
259 | 6 | public function withMeta($meta): EncoderInterface |
|
266 | |||
267 | /** |
||
268 | * @inheritdoc |
||
269 | */ |
||
270 | 2 | public function withJsonApiVersion(string $version = self::JSON_API_VERSION): EncoderInterface |
|
276 | |||
277 | /** |
||
278 | * @inheritdoc |
||
279 | */ |
||
280 | 2 | public function withJsonApiMeta($meta): EncoderInterface |
|
287 | |||
288 | /** |
||
289 | * @inheritdoc |
||
290 | */ |
||
291 | 1 | View Code Duplication | public function withRelationshipSelfLink($resource, string $relationshipName): EncoderInterface |
303 | |||
304 | /** |
||
305 | * @inheritdoc |
||
306 | */ |
||
307 | 1 | View Code Duplication | public function withRelationshipRelatedLink($resource, string $relationshipName): EncoderInterface |
319 | |||
320 | /** |
||
321 | * @inheritdoc |
||
322 | */ |
||
323 | 63 | public function encodeData($data): string |
|
333 | |||
334 | /** |
||
335 | * @inheritdoc |
||
336 | */ |
||
337 | 3 | public function encodeIdentifiers($data): string |
|
347 | |||
348 | /** |
||
349 | * @inheritdoc |
||
350 | */ |
||
351 | 3 | public function encodeError(ErrorInterface $error): string |
|
361 | |||
362 | /** |
||
363 | * @inheritdoc |
||
364 | */ |
||
365 | 3 | public function encodeErrors(iterable $errors): string |
|
375 | |||
376 | /** |
||
377 | * @inheritdoc |
||
378 | */ |
||
379 | 1 | public function encodeMeta($meta): string |
|
389 | |||
390 | /** |
||
391 | * @return FactoryInterface |
||
392 | */ |
||
393 | 71 | protected static function createFactory(): FactoryInterface |
|
397 | |||
398 | /** |
||
399 | * @return SchemaContainerInterface |
||
400 | */ |
||
401 | 67 | protected function getSchemaContainer(): SchemaContainerInterface |
|
405 | |||
406 | /** |
||
407 | * @return FactoryInterface |
||
408 | */ |
||
409 | 76 | protected function getFactory(): FactoryInterface |
|
413 | |||
414 | /** |
||
415 | * Reset to initial state. |
||
416 | */ |
||
417 | 78 | protected function reset(): void |
|
434 | |||
435 | /** |
||
436 | * @return bool |
||
437 | */ |
||
438 | 76 | protected function hasLinks(): bool |
|
442 | |||
443 | /** |
||
444 | * @return bool |
||
445 | */ |
||
446 | 76 | protected function hasProfile(): bool |
|
450 | |||
451 | /** |
||
452 | * @return iterable |
||
453 | */ |
||
454 | 5 | protected function getLinks(): iterable |
|
458 | |||
459 | /** |
||
460 | * @return iterable |
||
461 | */ |
||
462 | 1 | protected function getProfile(): iterable |
|
466 | |||
467 | /** |
||
468 | * @return bool |
||
469 | */ |
||
470 | 76 | protected function hasMeta(): bool |
|
474 | |||
475 | /** |
||
476 | * @return mixed |
||
477 | */ |
||
478 | 6 | public function getMeta() |
|
482 | |||
483 | /** |
||
484 | * @return bool |
||
485 | */ |
||
486 | 76 | protected function hasJsonApiVersion(): bool |
|
490 | |||
491 | /** |
||
492 | * @return string |
||
493 | */ |
||
494 | 2 | protected function getJsonApiVersion(): string |
|
498 | |||
499 | /** |
||
500 | * @return bool |
||
501 | */ |
||
502 | 76 | protected function hasJsonApiMeta(): bool |
|
506 | |||
507 | /** |
||
508 | * @return mixed |
||
509 | */ |
||
510 | 2 | protected function getJsonApiMeta() |
|
514 | |||
515 | /** |
||
516 | * @param object|iterable|null $data Data to encode. |
||
517 | * |
||
518 | * @return array |
||
519 | * |
||
520 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
521 | */ |
||
522 | 64 | protected function encodeDataToArray($data): array |
|
565 | |||
566 | /** |
||
567 | * @param object|iterable|null $data Data to encode. |
||
568 | * |
||
569 | * @return array |
||
570 | * |
||
571 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
572 | */ |
||
573 | 4 | protected function encodeIdentifiersToArray($data): array |
|
631 | |||
632 | /** |
||
633 | * @param ErrorInterface $error |
||
634 | * |
||
635 | * @return array |
||
636 | */ |
||
637 | 4 | protected function encodeErrorToArray(ErrorInterface $error): array |
|
654 | |||
655 | /** |
||
656 | * @param iterable $errors |
||
657 | * |
||
658 | * @return array |
||
659 | */ |
||
660 | 4 | protected function encodeErrorsToArray(iterable $errors): array |
|
681 | |||
682 | /** |
||
683 | * @param $meta |
||
684 | * |
||
685 | * @return array |
||
686 | */ |
||
687 | 2 | protected function encodeMetaToArray($meta): array |
|
706 | |||
707 | /** |
||
708 | * @param BaseWriterInterface $writer |
||
709 | * |
||
710 | * @return void |
||
711 | */ |
||
712 | 76 | protected function writeHeader(BaseWriterInterface $writer): void |
|
734 | |||
735 | /** |
||
736 | * @param BaseWriterInterface $writer |
||
737 | * |
||
738 | * @return void |
||
739 | */ |
||
740 | 74 | protected function writeFooter(BaseWriterInterface $writer): void |
|
743 | |||
744 | /** |
||
745 | * Encode array to JSON. |
||
746 | * |
||
747 | * @param array $document |
||
748 | * |
||
749 | * @return string |
||
750 | */ |
||
751 | 70 | protected function encodeToJson(array $document): string |
|
755 | |||
756 | /** |
||
757 | * @return string |
||
758 | */ |
||
759 | 76 | protected function getUrlPrefix(): string |
|
763 | |||
764 | /** |
||
765 | * @return array |
||
766 | */ |
||
767 | 67 | protected function getIncludePaths(): array |
|
771 | |||
772 | /** |
||
773 | * @return array |
||
774 | */ |
||
775 | 67 | protected function getFieldSets(): array |
|
779 | |||
780 | /** |
||
781 | * @return int |
||
782 | */ |
||
783 | 70 | protected function getEncodeOptions(): int |
|
787 | |||
788 | /** |
||
789 | * @return int |
||
790 | */ |
||
791 | 70 | protected function getEncodeDepth(): int |
|
795 | |||
796 | /** |
||
797 | * @return DocumentWriterInterface |
||
798 | */ |
||
799 | 67 | private function createDocumentWriter(): DocumentWriterInterface |
|
806 | |||
807 | /** |
||
808 | * @return ErrorWriterInterface |
||
809 | */ |
||
810 | 7 | private function createErrorWriter(): ErrorWriterInterface |
|
817 | |||
818 | /** |
||
819 | * @param iterable $iterable1 |
||
820 | * @param iterable $iterable2 |
||
821 | * |
||
822 | * @return iterable |
||
823 | */ |
||
824 | private function mergeIterables(iterable $iterable1, iterable $iterable2): iterable |
||
829 | } |
||
830 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: