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 Arr 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 Arr, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class Arr |
||
22 | { |
||
23 | /** |
||
24 | * Gets a dot-notated key from an array, with a default value if it does |
||
25 | * not exist. |
||
26 | * |
||
27 | * @param array $array The search array |
||
28 | * @param mixed $key The dot-notated key or array of keys |
||
29 | * @param string $default The default value |
||
30 | * |
||
31 | * @return mixed |
||
32 | * |
||
33 | * @throws \InvalidArgumentException |
||
34 | * @since 2.0 |
||
35 | */ |
||
36 | public static function get($array, $key, $default = null) |
||
83 | |||
84 | /** |
||
85 | * Set an array item (dot-notated) to the value. |
||
86 | * |
||
87 | * @param array $array The array to insert it into |
||
88 | * @param mixed $key The dot-notated key to set or array of keys |
||
89 | * @param mixed $value The value |
||
90 | * |
||
91 | * @return void |
||
92 | * @since 2.0 |
||
93 | */ |
||
94 | public static function set(&$array, $key, $value = null) |
||
128 | |||
129 | /** |
||
130 | * Pluck an array of values from an array. |
||
131 | * |
||
132 | * @param array $array collection of arrays to pluck from |
||
133 | * @param string $key key of the value to pluck |
||
134 | * @param string $index optional return array index key, true for original index |
||
135 | * |
||
136 | * @return array array of plucked values |
||
137 | * @since 2.0 |
||
138 | */ |
||
139 | public static function pluck($array, $key, $index = null) |
||
164 | |||
165 | /** |
||
166 | * Array_key_exists with a dot-notated key from an array. |
||
167 | * |
||
168 | * @param array $array The search array |
||
169 | * @param mixed $key The dot-notated key or array of keys |
||
170 | * |
||
171 | * @return mixed |
||
172 | * @since 2.0 |
||
173 | */ |
||
174 | public static function has($array, $key) |
||
188 | |||
189 | /** |
||
190 | * Unsets dot-notated key from an array |
||
191 | * |
||
192 | * @param array $array The search array |
||
193 | * @param mixed $key The dot-notated key or array of keys |
||
194 | * |
||
195 | * @return mixed |
||
196 | * @since 2.0 |
||
197 | */ |
||
198 | public static function delete(&$array, $key) |
||
236 | |||
237 | /** |
||
238 | * Converts a multi-dimensional associative array into an array of key => values with the provided field names |
||
239 | * |
||
240 | * @param array $assoc the array to convert |
||
241 | * @param string $key_field the field name of the key field |
||
242 | * @param string $val_field the field name of the value field |
||
243 | * |
||
244 | * @return array |
||
245 | * @throws \InvalidArgumentException |
||
246 | * @since 2.0 |
||
247 | */ |
||
248 | public static function assocToKeyval($assoc, $key_field, $val_field) |
||
266 | |||
267 | /** |
||
268 | * Converts the given 1 dimensional non-associative array to an associative |
||
269 | * array. |
||
270 | * |
||
271 | * The array given must have an even number of elements or null will be returned. |
||
272 | * |
||
273 | * Arr::to_assoc(array('foo','bar')); |
||
274 | * |
||
275 | * @param string $arr the array to change |
||
276 | * |
||
277 | * @return array|null the new array or null |
||
278 | * @throws \BadMethodCallException |
||
279 | * @since 2.0 |
||
280 | */ |
||
281 | public static function toAssoc($arr) |
||
296 | |||
297 | /** |
||
298 | * Checks if the given array is an assoc array. |
||
299 | * |
||
300 | * @param array $arr the array to check |
||
301 | * |
||
302 | * @return bool true if its an assoc array, false if not |
||
303 | * |
||
304 | * @throws \InvalidArgumentException |
||
305 | * @since 2.0 |
||
306 | */ |
||
307 | public static function isAssoc($arr) |
||
324 | |||
325 | /** |
||
326 | * Flattens a multi-dimensional associative array down into a 1 dimensional |
||
327 | * associative array. |
||
328 | * |
||
329 | * @param array $array the array to flatten |
||
330 | * @param string $glue what to glue the keys together with |
||
331 | * @param bool $reset whether to reset and start over on a new array |
||
332 | * @param bool $indexed whether to flatten only associative array's, or also indexed ones |
||
333 | * |
||
334 | * @return array |
||
335 | * @since 2.0 |
||
336 | */ |
||
337 | public static function flatten($array, $glue = ':', $reset = true, $indexed = true) |
||
363 | |||
364 | /** |
||
365 | * Flattens a multi-dimensional associative array down into a 1 dimensional |
||
366 | * associative array. |
||
367 | * |
||
368 | * @param array $array the array to flatten |
||
369 | * @param string $glue what to glue the keys together with |
||
370 | * @param bool $reset whether to reset and start over on a new array |
||
371 | * |
||
372 | * @return array |
||
373 | * @since 2.0 |
||
374 | */ |
||
375 | public static function flattenAssoc($array, $glue = ':', $reset = true) |
||
379 | |||
380 | /** |
||
381 | * Reverse a flattened array in its original form. |
||
382 | * |
||
383 | * @param array $array flattened array |
||
384 | * @param string $glue glue used in flattening |
||
385 | * |
||
386 | * @return array the unflattened array |
||
387 | * @since 2.0 |
||
388 | */ |
||
389 | public static function reverseFlatten($array, $glue = ':') |
||
423 | |||
424 | /** |
||
425 | * Filters an array on prefixed associative keys. |
||
426 | * |
||
427 | * @param array $array the array to filter. |
||
428 | * @param string $prefix prefix to filter on. |
||
429 | * @param bool $removePrefix whether to remove the prefix. |
||
430 | * |
||
431 | * @return array |
||
432 | * @since 2.0 |
||
433 | */ |
||
434 | View Code Duplication | public static function filterPrefixed($array, $prefix, $removePrefix = true) |
|
450 | |||
451 | /** |
||
452 | * Recursive version of PHP's array_filter() |
||
453 | * |
||
454 | * @param array $array the array to filter. |
||
455 | * @param \Callback $callback the callback that determines whether or not a value is filtered |
||
456 | * |
||
457 | * @return array |
||
458 | * @since 2.0 |
||
459 | */ |
||
460 | public static function filterRecursive($array, $callback = null) |
||
475 | |||
476 | /** |
||
477 | * Removes items from an array that match a key prefix. |
||
478 | * |
||
479 | * @param array $array the array to remove from |
||
480 | * @param string $prefix prefix to filter on |
||
481 | * |
||
482 | * @return array |
||
483 | * @since 2.0 |
||
484 | */ |
||
485 | public static function removePrefixed($array, $prefix) |
||
496 | |||
497 | /** |
||
498 | * Filters an array on suffixed associative keys. |
||
499 | * |
||
500 | * @param array $array the array to filter. |
||
501 | * @param string $suffix suffix to filter on. |
||
502 | * @param bool $removeSuffix whether to remove the suffix. |
||
503 | * |
||
504 | * @return array |
||
505 | * @since 2.0 |
||
506 | */ |
||
507 | View Code Duplication | public static function filterSuffixed($array, $suffix, $removeSuffix = true) |
|
523 | |||
524 | /** |
||
525 | * Removes items from an array that match a key suffix. |
||
526 | * |
||
527 | * @param array $array the array to remove from |
||
528 | * @param string $suffix suffix to filter on |
||
529 | * |
||
530 | * @return array |
||
531 | * @since 2.0 |
||
532 | */ |
||
533 | public static function removeSuffixed($array, $suffix) |
||
544 | |||
545 | /** |
||
546 | * Filters an array by an array of keys |
||
547 | * |
||
548 | * @param array $array the array to filter. |
||
549 | * @param array $keys the keys to filter |
||
550 | * @param bool $remove if true, removes the matched elements. |
||
551 | * |
||
552 | * @return array |
||
553 | * @since 2.0 |
||
554 | */ |
||
555 | public static function filterKeys($array, $keys, $remove = false) |
||
571 | |||
572 | /** |
||
573 | * Insert value(s) into an array, mostly an array_splice alias |
||
574 | * WARNING: original array is edited by reference, only boolean success is returned |
||
575 | * |
||
576 | * @param array &$original the original array (by reference) |
||
577 | * @param array|mixed $value the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
578 | * @param int $pos the numeric position at which to insert, negative to count from the end backwards |
||
579 | * |
||
580 | * @return bool false when array shorter then $pos, otherwise true |
||
581 | * @throws \InvalidArgumentException |
||
582 | * @since 2.0 |
||
583 | */ |
||
584 | public static function insert(array &$original, $value, $pos) |
||
595 | |||
596 | /** |
||
597 | * Insert value(s) into an array, mostly an array_splice alias |
||
598 | * WARNING: original array is edited by reference, only boolean success is returned |
||
599 | * |
||
600 | * @param array &$original the original array (by reference) |
||
601 | * @param array|mixed $values the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
602 | * @param int $pos the numeric position at which to insert, negative to count from the end backwards |
||
603 | * |
||
604 | * @return bool false when array shorter then $pos, otherwise true |
||
605 | * @since 2.0 |
||
606 | */ |
||
607 | public static function insertAssoc(array &$original, array $values, $pos) |
||
618 | |||
619 | /** |
||
620 | * Insert value(s) into an array before a specific key |
||
621 | * WARNING: original array is edited by reference, only boolean success is returned |
||
622 | * |
||
623 | * @param array &$original the original array (by reference) |
||
624 | * @param array|mixed $value the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
625 | * @param string|int $key the key before which to insert |
||
626 | * @param bool $isAssoc wether the input is an associative array |
||
627 | * |
||
628 | * @return bool false when key isn't found in the array, otherwise true |
||
629 | * |
||
630 | * @throws \InvalidArgumentException |
||
631 | * @since 2.0 |
||
632 | */ |
||
633 | View Code Duplication | public static function insertBeforeKey(array &$original, $value, $key, $isAssoc = false) |
|
644 | |||
645 | /** |
||
646 | * Insert value(s) into an array after a specific key |
||
647 | * WARNING: original array is edited by reference, only boolean success is returned |
||
648 | * |
||
649 | * @param array &$original the original array (by reference) |
||
650 | * @param array|mixed $value the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
651 | * @param string|int $key the key after which to insert |
||
652 | * @param bool $isAssoc wether the input is an associative array |
||
653 | * |
||
654 | * @return bool false when key isn't found in the array, otherwise true |
||
655 | * |
||
656 | * @throws \InvalidArgumentException |
||
657 | * @since 2.0 |
||
658 | */ |
||
659 | View Code Duplication | public static function insertAfterKey(array &$original, $value, $key, $isAssoc = false) |
|
674 | |||
675 | /** |
||
676 | * Insert value(s) into an array after a specific value (first found in array) |
||
677 | * |
||
678 | * @param array &$original the original array (by reference) |
||
679 | * @param array|mixed $value the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
680 | * @param string|int $search the value after which to insert |
||
681 | * @param bool $isAssoc wether the input is an associative array |
||
682 | * |
||
683 | * @return bool false when value isn't found in the array, otherwise true |
||
684 | * |
||
685 | * @throws \InvalidArgumentException |
||
686 | * @since 2.0 |
||
687 | */ |
||
688 | View Code Duplication | public static function insertAfterValue(array &$original, $value, $search, $isAssoc = false) |
|
699 | |||
700 | /** |
||
701 | * Insert value(s) into an array before a specific value (first found in array) |
||
702 | * |
||
703 | * @param array &$original the original array (by reference) |
||
704 | * @param array|mixed $value the value(s) to insert, if you want to insert an array it needs to be in an array itself |
||
705 | * @param string|int $search the value after which to insert |
||
706 | * @param bool $isAssoc wether the input is an associative array |
||
707 | * |
||
708 | * @return bool false when value isn't found in the array, otherwise true |
||
709 | * |
||
710 | * @throws \InvalidArgumentException |
||
711 | * @since 2.0 |
||
712 | */ |
||
713 | View Code Duplication | public static function insertBeforeValue(array &$original, $value, $search, $isAssoc = false) |
|
724 | |||
725 | /** |
||
726 | * Sorts a multi-dimensional array by it's values. |
||
727 | * |
||
728 | * @param array $array The array to fetch from |
||
729 | * @param string $key The key to sort by |
||
730 | * @param string $order The order (asc or desc) |
||
731 | * @param int $sortFlags The php sort type flag |
||
732 | * |
||
733 | * @return array |
||
734 | * |
||
735 | * @throws \InvalidArgumentException |
||
736 | * @since 2.0 |
||
737 | */ |
||
738 | public static function sort($array, $key, $order = 'asc', $sortFlags = SORT_REGULAR) |
||
779 | |||
780 | /** |
||
781 | * Sorts an array on multitiple values, with deep sorting support. |
||
782 | * |
||
783 | * @param array $array collection of arrays/objects to sort |
||
784 | * @param array $conditions sorting conditions |
||
785 | * @param bool $ignore_case wether to sort case insensitive |
||
786 | * |
||
787 | * @return array |
||
788 | * @since 2.0 |
||
789 | */ |
||
790 | public static function multisort($array, $conditions, $ignore_case = false) |
||
816 | |||
817 | /** |
||
818 | * Find the average of an array |
||
819 | * |
||
820 | * @param array $array the array containing the values |
||
821 | * |
||
822 | * @return int the average value |
||
823 | * @since 2.0 |
||
824 | */ |
||
825 | public static function average($array) |
||
835 | |||
836 | /** |
||
837 | * Replaces key names in an array by names in $replace |
||
838 | * |
||
839 | * @param array $source the array containing the key/value combinations |
||
840 | * @param array|string $replace to replace or array containing the replacement keys |
||
841 | * @param string $new_key the replacement key |
||
842 | * |
||
843 | * @return array the array with the new keys |
||
844 | * |
||
845 | * @throws \InvalidArgumentException |
||
846 | * @since 2.0 |
||
847 | */ |
||
848 | public static function replaceKey($source, $replace, $new_key = null) |
||
876 | |||
877 | /** |
||
878 | * Merge 2 arrays recursively, differs in 2 important ways from array_merge_recursive() |
||
879 | * - When there's 2 different values and not both arrays, the latter value overwrites the earlier |
||
880 | * instead of merging both into an array |
||
881 | * - Numeric keys that don't conflict aren't changed, only when a numeric key already exists is the |
||
882 | * value added using array_push() |
||
883 | * |
||
884 | * Expects multiple variables all of which must be arrays |
||
885 | * |
||
886 | * @return array |
||
887 | * @throws \InvalidArgumentException |
||
888 | * @since 2.0 |
||
889 | */ |
||
890 | public static function merge() |
||
927 | |||
928 | /** |
||
929 | * Merge 2 arrays recursively, differs in 2 important ways from array_merge_recursive() |
||
930 | * - When there's 2 different values and not both arrays, the latter value overwrites the earlier |
||
931 | * instead of merging both into an array |
||
932 | * - Numeric keys are never changed |
||
933 | * |
||
934 | * Expects multiple variables all of which must be arrays |
||
935 | * |
||
936 | * @return array |
||
937 | * @throws \InvalidArgumentException |
||
938 | * @since 2.0 |
||
939 | */ |
||
940 | public static function mergeAssoc() |
||
972 | |||
973 | /** |
||
974 | * Prepends a value with an asociative key to an array. |
||
975 | * Will overwrite if the value exists. |
||
976 | * |
||
977 | * @param array &$arr the array to prepend to |
||
978 | * @param string|array $key the key or array of keys and values |
||
979 | * @param mixed $value the value to prepend |
||
980 | * @since 2.0 |
||
981 | */ |
||
982 | public static function prepend(&$arr, $key, $value = null) |
||
986 | |||
987 | /** |
||
988 | * Recursive in_array |
||
989 | * |
||
990 | * @param mixed $needle what to search for |
||
991 | * @param array $haystack array to search in |
||
992 | * @param bool $strict |
||
993 | * |
||
994 | * @return bool wether the needle is found in the haystack. |
||
995 | * @since 2.0 |
||
996 | */ |
||
997 | public static function inArrayRecursive($needle, $haystack, $strict = false) |
||
1017 | |||
1018 | /** |
||
1019 | * Checks if the given array is a multidimensional array. |
||
1020 | * |
||
1021 | * @param array $arr the array to check |
||
1022 | * @param bool $all_keys if true, check that all elements are arrays |
||
1023 | * |
||
1024 | * @return bool true if its a multidimensional array, false if not |
||
1025 | * @since 2.0 |
||
1026 | */ |
||
1027 | public static function isMulti($arr, $all_keys = false) |
||
1032 | |||
1033 | /** |
||
1034 | * Searches the array for a given value and returns the |
||
1035 | * corresponding key or default value. |
||
1036 | * If $recursive is set to true, then the Arr::search() |
||
1037 | * function will return a delimiter-notated key using $delimiter. |
||
1038 | * |
||
1039 | * @param array $array The search array |
||
1040 | * @param mixed $value The searched value |
||
1041 | * @param string $default The default value |
||
1042 | * @param bool $recursive Whether to get keys recursive |
||
1043 | * @param string $delimiter The delimiter, when $recursive is true |
||
1044 | * @param bool $strict If true, do a strict key comparison |
||
1045 | * |
||
1046 | * @return mixed |
||
1047 | * |
||
1048 | * @throws \InvalidArgumentException |
||
1049 | * @since 2.0 |
||
1050 | */ |
||
1051 | public static function search($array, $value, $default = null, $recursive = true, $delimiter = '.', $strict = false) |
||
1090 | |||
1091 | /** |
||
1092 | * Returns only unique values in an array. It does not sort. First value is used. |
||
1093 | * |
||
1094 | * @param array $arr the array to dedup |
||
1095 | * |
||
1096 | * @return array array with only de-duped values |
||
1097 | * @since 2.0 |
||
1098 | */ |
||
1099 | public static function unique($arr) |
||
1125 | |||
1126 | /** |
||
1127 | * Calculate the sum of an array |
||
1128 | * |
||
1129 | * @param array $array the array containing the values |
||
1130 | * @param string $key key of the value to pluck |
||
1131 | * |
||
1132 | * @return int the sum value |
||
1133 | * |
||
1134 | * @throws \InvalidArgumentException |
||
1135 | * @since 2.0 |
||
1136 | */ |
||
1137 | public static function sum($array, $key) |
||
1146 | |||
1147 | /** |
||
1148 | * Returns the array with all numeric keys re-indexed, and string keys untouched |
||
1149 | * |
||
1150 | * @param array $arr the array to reindex |
||
1151 | * |
||
1152 | * @return array reindexed array |
||
1153 | * @since 2.0 |
||
1154 | */ |
||
1155 | public static function reIndex($arr) |
||
1167 | |||
1168 | /** |
||
1169 | * Get the previous value or key from an array using the current array key |
||
1170 | * |
||
1171 | * @param array $array the array containing the values |
||
1172 | * @param string $key key of the current entry to use as reference |
||
1173 | * @param bool $getValue if true, return the previous value instead of the previous key |
||
1174 | * @param bool $strict if true, do a strict key comparison |
||
1175 | * |
||
1176 | * @return mixed the value in the array, null if there is no previous value, or false if the key doesn't exist |
||
1177 | * |
||
1178 | * @throws \InvalidArgumentException |
||
1179 | * @since 2.0 |
||
1180 | */ |
||
1181 | public static function previousByKey($array, $key, $getValue = false, $strict = false) |
||
1208 | |||
1209 | /** |
||
1210 | * Get the next value or key from an array using the current array key |
||
1211 | * |
||
1212 | * @param array $array the array containing the values |
||
1213 | * @param string $key key of the current entry to use as reference |
||
1214 | * @param bool $getValue if true, return the next value instead of the next key |
||
1215 | * @param bool $strict if true, do a strict key comparison |
||
1216 | * |
||
1217 | * @return mixed the value in the array, null if there is no next value, or false if the key doesn't exist |
||
1218 | * |
||
1219 | * @throws \InvalidArgumentException |
||
1220 | * @since 2.0 |
||
1221 | */ |
||
1222 | public static function nextByKey($array, $key, $getValue = false, $strict = false) |
||
1249 | |||
1250 | /** |
||
1251 | * Get the previous value or key from an array using the current array value |
||
1252 | * |
||
1253 | * @param array $array the array containing the values |
||
1254 | * @param string $value value of the current entry to use as reference |
||
1255 | * @param bool $getValue if true, return the previous value instead of the previous key |
||
1256 | * @param bool $strict if true, do a strict key comparison |
||
1257 | * |
||
1258 | * @return mixed the value in the array, null if there is no previous value, or false if the key doesn't exist |
||
1259 | * |
||
1260 | * @throws \InvalidArgumentException |
||
1261 | * @since 2.0 |
||
1262 | */ |
||
1263 | public static function previousByValue($array, $value, $getValue = true, $strict = false) |
||
1290 | |||
1291 | /** |
||
1292 | * Get the next value or key from an array using the current array value |
||
1293 | * |
||
1294 | * @param array $array the array containing the values |
||
1295 | * @param string $value value of the current entry to use as reference |
||
1296 | * @param bool $getValue if true, return the next value instead of the next key |
||
1297 | * @param bool $strict if true, do a strict key comparison |
||
1298 | * |
||
1299 | * @return mixed the value in the array, null if there is no next value, or false if the key doesn't exist |
||
1300 | * |
||
1301 | * @throws \InvalidArgumentException |
||
1302 | * @since 2.0 |
||
1303 | */ |
||
1304 | public static function nextByValue($array, $value, $getValue = true, $strict = false) |
||
1331 | |||
1332 | /** |
||
1333 | * Return the subset of the array defined by the supplied keys. |
||
1334 | * |
||
1335 | * Returns $default for missing keys, as with Arr::get() |
||
1336 | * |
||
1337 | * @param array $array the array containing the values |
||
1338 | * @param array $keys list of keys (or indices) to return |
||
1339 | * @param mixed $default value of missing keys; default null |
||
1340 | * |
||
1341 | * @return array An array containing the same set of keys provided. |
||
1342 | * @since 2.0 |
||
1343 | */ |
||
1344 | public static function subset(array $array, array $keys, $default = null) |
||
1355 | } |
||
1356 |
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.