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 BundleStorage 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 BundleStorage, and based on these observations, apply Extract Interface, too.
| 1 | <?php namespace Limoncello\l10n\Messages; |
||
| 24 | class BundleStorage implements BundleStorageInterface |
||
| 25 | { |
||
| 26 | /** Encode index */ |
||
| 27 | const INDEX_DEFAULT_LOCALE = 0; |
||
| 28 | |||
| 29 | /** Encode index */ |
||
| 30 | const INDEX_DATA = self::INDEX_DEFAULT_LOCALE + 1; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @var array |
||
| 34 | 2 | */ |
|
| 35 | private $encodedStorage; |
||
| 36 | 2 | ||
| 37 | 2 | /** |
|
| 38 | * @var string[] |
||
| 39 | */ |
||
| 40 | private $locales; |
||
| 41 | |||
| 42 | 2 | /** |
|
| 43 | * @var string |
||
| 44 | 2 | */ |
|
| 45 | 2 | private $defaultLocale; |
|
| 46 | 2 | ||
| 47 | /** |
||
| 48 | 2 | * @param array $encodedStorage |
|
| 49 | */ |
||
| 50 | 2 | public function __construct(array $encodedStorage) |
|
| 54 | |||
| 55 | /** |
||
| 56 | 2 | * @inheritdoc |
|
| 57 | */ |
||
| 58 | 2 | public function has(string $locale, string $namespace, string $key): bool |
|
| 70 | |||
| 71 | 1 | /** |
|
| 72 | 1 | * @inheritdoc |
|
| 73 | */ |
||
| 74 | 1 | public function get(string $locale, string $namespace, string $key) |
|
| 85 | |||
| 86 | 1 | /** |
|
| 87 | * @inheritdoc |
||
| 88 | 1 | */ |
|
| 89 | public function hasResources(string $locale, string $namespace): bool |
||
| 97 | |||
| 98 | /** |
||
| 99 | * @inheritdoc |
||
| 100 | */ |
||
| 101 | public function getResources(string $locale, string $namespace): array |
||
| 111 | 2 | ||
| 112 | 2 | /** |
|
| 113 | 2 | * @inheritdoc |
|
| 114 | 2 | */ |
|
| 115 | 2 | public function getDefaultLocale(): string |
|
| 119 | 2 | ||
| 120 | 2 | /** |
|
| 121 | 2 | * @return array |
|
| 122 | 2 | */ |
|
| 123 | protected function getEncodedStorage(): array |
||
| 127 | |||
| 128 | 2 | /** |
|
| 129 | 2 | * @param string[] $locales |
|
| 130 | * @param string $locale |
||
| 131 | 2 | * @param string $defaultLocale |
|
| 132 | * |
||
| 133 | 2 | * @return string |
|
| 134 | */ |
||
| 135 | protected function lookupLocale(array $locales, string $locale, string $defaultLocale): string |
||
| 139 | |||
| 140 | /** |
||
| 141 | * @return string[] |
||
| 142 | */ |
||
| 143 | protected function getLocales(): array |
||
| 147 | |||
| 148 | /** |
||
| 149 | * @param array $encodedStorage |
||
| 150 | * |
||
| 151 | * @return self |
||
| 152 | */ |
||
| 153 | protected function setEncodedStorage(array $encodedStorage): self |
||
| 169 | |||
| 170 | /** |
||
| 171 | * @param array $encodedData |
||
| 172 | * |
||
| 173 | * @return bool |
||
| 174 | */ |
||
| 175 | View Code Duplication | private function checkEncodedData(array $encodedData): bool |
|
| 187 | |||
| 188 | /** |
||
| 189 | * @param array $namespaceResources |
||
| 190 | * |
||
| 191 | * @return bool |
||
| 192 | */ |
||
| 193 | View Code Duplication | private function checkNamespaceResources(array $namespaceResources): bool |
|
| 205 | |||
| 206 | /** |
||
| 207 | * @param array $resources |
||
| 208 | * |
||
| 209 | * @return bool |
||
| 210 | */ |
||
| 211 | private function checkResources(array $resources): bool |
||
| 221 | |||
| 222 | /** |
||
| 223 | * @param string $key |
||
| 224 | * @param array $valueAndLocale |
||
| 225 | * |
||
| 226 | * @return bool |
||
| 227 | */ |
||
| 228 | private function checkPair(string $key, array $valueAndLocale): bool |
||
| 235 | |||
| 236 | /** |
||
| 237 | * @param array $valueAndLocale |
||
| 238 | * |
||
| 239 | * @return bool |
||
| 240 | */ |
||
| 241 | private function checkValueWithLocale(array $valueAndLocale): bool |
||
| 250 | |||
| 251 | /** |
||
| 252 | * @param mixed $value |
||
| 253 | * |
||
| 254 | * @return bool |
||
| 255 | */ |
||
| 256 | private function checkNonEmptyStringOrInt($value): bool |
||
| 262 | |||
| 263 | /** |
||
| 264 | * @param mixed $value |
||
| 265 | * |
||
| 266 | * @return bool |
||
| 267 | */ |
||
| 268 | private function checkNonEmptyString($value): bool |
||
| 274 | } |
||
| 275 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..