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 GeocoderResult 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 GeocoderResult, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
22 | class GeocoderResult |
||
23 | { |
||
24 | /** |
||
25 | * @var string|null |
||
26 | */ |
||
27 | private $placeId; |
||
28 | |||
29 | /** |
||
30 | * @var AddressComponent[] |
||
31 | */ |
||
32 | private $addressComponents = []; |
||
33 | |||
34 | /** |
||
35 | * @var string|null |
||
36 | */ |
||
37 | private $formattedAddress; |
||
38 | |||
39 | /** |
||
40 | * @var string[] |
||
41 | */ |
||
42 | private $postcodeLocalities = []; |
||
43 | |||
44 | /** |
||
45 | * @var Geometry|null |
||
46 | */ |
||
47 | private $geometry; |
||
48 | |||
49 | /** |
||
50 | * @var bool|null |
||
51 | */ |
||
52 | private $partialMatch; |
||
53 | |||
54 | /** |
||
55 | * @var string[] |
||
56 | */ |
||
57 | private $types = []; |
||
58 | |||
59 | /** |
||
60 | * @return bool |
||
61 | */ |
||
62 | 8 | public function hasPlaceId() |
|
66 | |||
67 | /** |
||
68 | * @return string|null |
||
69 | */ |
||
70 | 136 | public function getPlaceId() |
|
74 | |||
75 | /** |
||
76 | * @param string|null $placeId |
||
77 | */ |
||
78 | 4 | public function setPlaceId($placeId) |
|
82 | |||
83 | /** |
||
84 | * @param string|null $type |
||
85 | * |
||
86 | * @return bool |
||
87 | */ |
||
88 | 24 | public function hasAddressComponents($type = null) |
|
94 | |||
95 | /** |
||
96 | * @param string|null $type |
||
97 | * |
||
98 | * @return AddressComponent[] |
||
99 | */ |
||
100 | 152 | View Code Duplication | public function getAddressComponents($type = null) |
116 | |||
117 | /** |
||
118 | * @param AddressComponent[] $addressComponents |
||
119 | */ |
||
120 | 12 | public function setAddressComponents(array $addressComponents) |
|
125 | |||
126 | /** |
||
127 | * @param AddressComponent[] $addressComponents |
||
128 | */ |
||
129 | 12 | public function addAddressComponents(array $addressComponents) |
|
135 | |||
136 | /** |
||
137 | * @param AddressComponent $addressComponent |
||
138 | * |
||
139 | * @return bool |
||
140 | */ |
||
141 | 20 | public function hasAddressComponent(AddressComponent $addressComponent) |
|
145 | |||
146 | /** |
||
147 | * @param AddressComponent $addressComponent |
||
148 | */ |
||
149 | 20 | public function addAddressComponent(AddressComponent $addressComponent) |
|
155 | |||
156 | /** |
||
157 | * @param AddressComponent $addressComponent |
||
158 | */ |
||
159 | 4 | public function removeAddressComponent(AddressComponent $addressComponent) |
|
160 | { |
||
161 | 4 | unset($this->addressComponents[array_search($addressComponent, $this->addressComponents, true)]); |
|
162 | 4 | $this->addressComponents = empty($this->addressComponents) ? [] : array_values($this->addressComponents); |
|
163 | 4 | } |
|
164 | |||
165 | /** |
||
166 | * @return bool |
||
167 | */ |
||
168 | 12 | public function hasFormattedAddress() |
|
172 | |||
173 | /** |
||
174 | * @return string|null |
||
175 | */ |
||
176 | 140 | public function getFormattedAddress() |
|
180 | |||
181 | /** |
||
182 | * @param string|null $formattedAddress |
||
183 | */ |
||
184 | 8 | public function setFormattedAddress($formattedAddress = null) |
|
188 | |||
189 | /** |
||
190 | * @return bool |
||
191 | */ |
||
192 | 20 | public function hasPostcodeLocalities() |
|
196 | |||
197 | /** |
||
198 | * @return string[] |
||
199 | */ |
||
200 | 20 | public function getPostcodeLocalities() |
|
204 | |||
205 | /** |
||
206 | * @param string[] $postcodeLocalities |
||
207 | */ |
||
208 | 8 | public function setPostcodeLocalities(array $postcodeLocalities) |
|
213 | |||
214 | /** |
||
215 | * @param string[] $postcodeLocalities |
||
216 | */ |
||
217 | 8 | public function addPostcodeLocalities(array $postcodeLocalities) |
|
223 | |||
224 | /** |
||
225 | * @param string $postcodeLocality |
||
226 | * |
||
227 | * @return bool |
||
228 | */ |
||
229 | 16 | public function hasPostcodeLocality($postcodeLocality) |
|
233 | |||
234 | /** |
||
235 | * @param string $postcodeLocality |
||
236 | */ |
||
237 | 16 | public function addPostcodeLocality($postcodeLocality) |
|
243 | |||
244 | /** |
||
245 | * @param string $postcodeLocality |
||
246 | */ |
||
247 | 4 | public function removePostcodeLocality($postcodeLocality) |
|
248 | { |
||
249 | 4 | unset($this->postcodeLocalities[array_search($postcodeLocality, $this->postcodeLocalities, true)]); |
|
250 | 4 | $this->postcodeLocalities = empty($this->postcodeLocalities) ? [] : array_values($this->postcodeLocalities); |
|
251 | 4 | } |
|
252 | |||
253 | /** |
||
254 | * @return bool |
||
255 | */ |
||
256 | 12 | public function hasGeometry() |
|
260 | |||
261 | /** |
||
262 | * @return Geometry|null |
||
263 | */ |
||
264 | 140 | public function getGeometry() |
|
268 | |||
269 | /** |
||
270 | * @param Geometry|null $geometry |
||
271 | */ |
||
272 | 8 | public function setGeometry(Geometry $geometry = null) |
|
276 | |||
277 | /** |
||
278 | * @return bool |
||
279 | */ |
||
280 | 12 | public function hasPartialMatch() |
|
284 | |||
285 | /** |
||
286 | * @return bool |
||
287 | */ |
||
288 | 140 | public function isPartialMatch() |
|
292 | |||
293 | /** |
||
294 | * @param bool|null $partialMatch |
||
295 | */ |
||
296 | 8 | public function setPartialMatch($partialMatch = null) |
|
300 | |||
301 | /** |
||
302 | * @return bool |
||
303 | */ |
||
304 | 20 | public function hasTypes() |
|
308 | |||
309 | /** |
||
310 | * @return string[] |
||
311 | */ |
||
312 | 148 | public function getTypes() |
|
316 | |||
317 | /** |
||
318 | * @param string[] $types |
||
319 | */ |
||
320 | 8 | public function setTypes(array $types) |
|
325 | |||
326 | /** |
||
327 | * @param string[] $types |
||
328 | */ |
||
329 | 8 | public function addTypes(array $types) |
|
335 | |||
336 | /** |
||
337 | * @param string $type |
||
338 | * |
||
339 | * @return bool |
||
340 | */ |
||
341 | 16 | public function hasType($type) |
|
345 | |||
346 | /** |
||
347 | * @param string $type |
||
348 | */ |
||
349 | 16 | public function addType($type) |
|
355 | |||
356 | /** |
||
357 | * @param string $type |
||
358 | */ |
||
359 | 4 | public function removeType($type) |
|
364 | } |
||
365 |
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.