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 Collection 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 Collection, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
7 | class Collection extends BaseCollection |
||
8 | { |
||
9 | /** |
||
10 | * Static helper method to instantiate a new collection. Useful for when you |
||
11 | * want to immediately chain a method. Eg: Collection::make([1, 2, 3])->map(...). |
||
12 | * |
||
13 | * @param array $initial |
||
14 | * |
||
15 | * @return Collection |
||
16 | */ |
||
17 | public static function make(array $initial) |
||
21 | |||
22 | /** |
||
23 | * Get a PHP style array from the current collection. |
||
24 | * |
||
25 | * @return array |
||
26 | */ |
||
27 | public function toArray() |
||
31 | |||
32 | /** |
||
33 | * Whether the collection has the specified key, and/or value associated |
||
34 | * with the specified key. |
||
35 | * |
||
36 | * @param string $key |
||
37 | * @param mixed $value |
||
38 | * |
||
39 | * @return bool |
||
40 | */ |
||
41 | public function has($key, $value = null) |
||
49 | |||
50 | /** |
||
51 | * Get the value associated with the specified key. |
||
52 | * |
||
53 | * @param string $key |
||
54 | * |
||
55 | * @throws \Enzyme\Collection\CollectionException If the key does not exist. |
||
56 | * |
||
57 | * @return mixed |
||
58 | */ |
||
59 | public function get($key) |
||
69 | |||
70 | /** |
||
71 | * Get the value associated with the specified key or return a default value |
||
72 | * instead if it does not exist. |
||
73 | * |
||
74 | * @param string $key |
||
75 | * @param mixed $default |
||
76 | * |
||
77 | * @return mixed |
||
78 | */ |
||
79 | public function getOrDefault($key, $default = null) |
||
87 | |||
88 | /** |
||
89 | * Execute the given callback function for each element in this collection. |
||
90 | * |
||
91 | * @param Closure $fn |
||
92 | */ |
||
93 | public function each(Closure $fn) |
||
101 | |||
102 | /** |
||
103 | * Execute the given callback function for each element in this collection |
||
104 | * and save the results to a new collection. |
||
105 | * |
||
106 | * @param Closure $fn |
||
107 | * |
||
108 | * @return \Enzyme\Collection\Collection |
||
109 | */ |
||
110 | View Code Duplication | public function map(Closure $fn) |
|
119 | |||
120 | /** |
||
121 | * Execute the given callback function for each element in this collection |
||
122 | * and save the results to a new collection with the specified key. The |
||
123 | * callback function should return a 1 element associative array, eg: |
||
124 | * ['key' => 'value'] to be mapped. |
||
125 | * |
||
126 | * @param Closure $fn |
||
127 | * |
||
128 | * @return \Enzyme\Collection\Collection |
||
129 | */ |
||
130 | public function mapWithKey(Closure $fn) |
||
148 | |||
149 | /** |
||
150 | * Pluck out all values in this collection which have the specified key. |
||
151 | * |
||
152 | * @param string $pluck_key |
||
153 | * @param bool $deep Whether to traverse into sub-arrays. |
||
154 | * |
||
155 | * @return \Enzyme\Collection\Collection |
||
156 | */ |
||
157 | public function pluck($pluck_key, $deep = true) |
||
161 | |||
162 | /** |
||
163 | * Get the number of elements in this collection. |
||
164 | * |
||
165 | * @return int |
||
166 | */ |
||
167 | public function count() |
||
171 | |||
172 | /** |
||
173 | * Whether this collection is empty. |
||
174 | * |
||
175 | * @return bool |
||
176 | */ |
||
177 | public function isEmpty() |
||
181 | |||
182 | /** |
||
183 | * Get the value of the first element in this collection. |
||
184 | * |
||
185 | * @throws \Enzyme\Collection\CollectionException If the collection is empty. |
||
186 | * |
||
187 | * @return mixed |
||
188 | */ |
||
189 | public function first() |
||
199 | |||
200 | /** |
||
201 | * Get the value of the first element in this collection or return the |
||
202 | * default value specified if the collection is empty. |
||
203 | * |
||
204 | * @param mixed $default |
||
205 | * |
||
206 | * @return mixed |
||
207 | */ |
||
208 | public function firstOrDefault($default = null) |
||
216 | |||
217 | /** |
||
218 | * Get the value of the last element in this collection. |
||
219 | * |
||
220 | * @throws \Enzyme\Collection\CollectionException If the collection is empty. |
||
221 | * |
||
222 | * @return mixed |
||
223 | */ |
||
224 | public function last() |
||
238 | |||
239 | /** |
||
240 | * Get the value of the last element in this collection or return the |
||
241 | * default value specified if the collection is empty. |
||
242 | * |
||
243 | * @param mixed $default |
||
244 | * |
||
245 | * @return mixed |
||
246 | */ |
||
247 | public function lastOrDefault($default = null) |
||
255 | |||
256 | /** |
||
257 | * Get a new collection of only the elements in the current collection |
||
258 | * that have the specified keys. |
||
259 | * |
||
260 | * @param array $keys |
||
261 | * |
||
262 | * @return \Enzyme\Collection\Collection |
||
263 | */ |
||
264 | public function only(array $keys) |
||
270 | |||
271 | /** |
||
272 | * Get a new collection of all the elements in the current collection |
||
273 | * except those that have the specified keys. |
||
274 | * |
||
275 | * @param array $keys |
||
276 | * |
||
277 | * @return \Enzyme\Collection\Collection |
||
278 | */ |
||
279 | public function except(array $keys) |
||
285 | |||
286 | /** |
||
287 | * Return a new collection with the current collection's elements plus the |
||
288 | * given value pushed onto the end of the array. |
||
289 | * |
||
290 | * @param mixed $value |
||
291 | * |
||
292 | * @return \Enzyme\Collection\Collection |
||
293 | */ |
||
294 | public function push($value) |
||
301 | |||
302 | /** |
||
303 | * Return a new collection with the current collection's elements plus the |
||
304 | * given key and value pushed onto the end of the array. |
||
305 | * |
||
306 | * @param string $key |
||
307 | * @param mixed $value |
||
308 | * |
||
309 | * @return \Enzyme\Collection\Collection |
||
310 | */ |
||
311 | public function pushWithKey($key, $value) |
||
318 | |||
319 | /** |
||
320 | * Return a new collection with the current collection's elements plus the |
||
321 | * given array pushed onto the end of the array. |
||
322 | * |
||
323 | * @param array $data |
||
324 | * |
||
325 | * @return \Enzyme\Collection\Collection |
||
326 | */ |
||
327 | public function pushArray(array $data) |
||
340 | |||
341 | /** |
||
342 | * Return a new collection with a subset of all the current collection's |
||
343 | * elements that pass the given callback functions truth test. |
||
344 | * |
||
345 | * @param Closure $fn |
||
346 | * |
||
347 | * @return \Enzyme\Collection\Collection |
||
348 | */ |
||
349 | View Code Duplication | public function filter(Closure $fn) |
|
363 | |||
364 | /** |
||
365 | * Sort the collection using the provided callback function. Same expected |
||
366 | * parameters and the PHP usort function. |
||
367 | * |
||
368 | * @param Closure $fn |
||
369 | * |
||
370 | * @return \Enzyme\Collection\Collection |
||
371 | */ |
||
372 | public function sort(Closure $fn) |
||
385 | |||
386 | /** |
||
387 | * Whether this collection has the specified number of elements within the |
||
388 | * given range or equal too or above the minimum value specified. |
||
389 | * |
||
390 | * @param int $min |
||
391 | * @param int $max Default is null. |
||
392 | * |
||
393 | * @return bool |
||
394 | */ |
||
395 | public function hasCount($min, $max = null) |
||
404 | |||
405 | /** |
||
406 | * Get a list of the keys used by this collection. |
||
407 | * |
||
408 | * @return array |
||
409 | */ |
||
410 | public function keys() |
||
414 | |||
415 | /** |
||
416 | * Checks whether the specified key exists in the given collection. |
||
417 | * |
||
418 | * @param string $key |
||
419 | * @param array $collection |
||
420 | * |
||
421 | * @return bool |
||
422 | */ |
||
423 | protected static function keyExists($key, array $collection) |
||
427 | |||
428 | /** |
||
429 | * Pluck all the values that have the specified key from the given |
||
430 | * collection. |
||
431 | * |
||
432 | * @param array $collection |
||
433 | * @param string $pluck_key |
||
434 | * @param bool $deep Whether to traverse into sub-arrays. |
||
435 | * |
||
436 | * @return \Enzyme\Collection\Collection |
||
437 | */ |
||
438 | protected static function pluckKey(array $collection, $pluck_key, $deep) |
||
463 | } |
||
464 |
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.