Complex classes like Arrgh 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 Arrgh, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | class Arrgh implements \ArrayAccess, \Iterator |
||
35 | { |
||
36 | const PHP_SORT_DIRECTION_56 = 1; |
||
37 | const PHP_SORT_DIRECTION_7 = -1; |
||
38 | |||
39 | private $array; |
||
40 | private $array_position; |
||
41 | private $original_array; |
||
42 | private $terminate; |
||
43 | private $keep_once; |
||
44 | private $last_value; |
||
45 | |||
46 | private static $php_version; |
||
47 | private static $php_sort_direction; |
||
48 | |||
49 | /* Creates a new arrgh array */ |
||
50 | public function __construct($array = []) |
||
60 | |||
61 | /* Starts object calls */ |
||
62 | public function __call($method, $args) |
||
66 | |||
67 | /* Returns an array */ |
||
68 | public function toArray() |
||
78 | |||
79 | public function keep() |
||
97 | |||
98 | /* ArrayAccess */ |
||
99 | public function offsetExists($offset) |
||
103 | |||
104 | /* ArrayAccess */ |
||
105 | public function offsetGet($offset) |
||
109 | |||
110 | /* ArrayAccess */ |
||
111 | public function offsetSet($offset, $value) |
||
119 | |||
120 | /* ArrayAccess */ |
||
121 | public function offsetUnset($offset) |
||
125 | |||
126 | /* Iterator */ |
||
127 | public function current() |
||
135 | |||
136 | /* Iterator */ |
||
137 | public function key() |
||
141 | |||
142 | /* Iterator */ |
||
143 | public function next() |
||
147 | |||
148 | /* Iterator */ |
||
149 | public function rewind() |
||
153 | |||
154 | /* Iterator */ |
||
155 | public function valid() |
||
159 | |||
160 | /* Creates a new arr array. Synonym for: chain() */ |
||
161 | public static function arr($array = []) |
||
165 | |||
166 | /* Creates a new arrgh array. Synonym for: arr() */ |
||
167 | public static function chain($array = []) |
||
171 | |||
172 | /* Starts object calls */ |
||
173 | public static function __callStatic($method, $args) |
||
186 | |||
187 | public static function allFunctions() |
||
199 | |||
200 | public static function getSortDirection($direction = null) |
||
211 | |||
212 | /* Wraps a callable with the purpose of fixing bad PHP sort implementations */ |
||
213 | private static function wrapCallable(Closure $callable) |
||
222 | |||
223 | /* Based on input method finds handler, function and post handler */ |
||
224 | private static function findFunction($method) |
||
251 | |||
252 | /* Transforms the incoming calls to native calls */ |
||
253 | private static function invoke($method, $args, $object = null) |
||
319 | |||
320 | /* Handles special case: asort - In PHP5 reverses equals ("arsort" doen't mess up for some reason) */ |
||
321 | private static function handleCaseAsort(&$matching_handler, &$matching_function, &$post_handler, &$args) |
||
326 | |||
327 | /* Handles special case: array_column - Native array_column filters away null values. |
||
328 | * That means you cannot use array_column for multisort since array size no longer matches. |
||
329 | * This version of array_column returns null if the column is missing. */ |
||
330 | private static function handleCaseArrayColumn(&$matching_handler, &$matching_function, &$post_handler, &$args) |
||
350 | |||
351 | /* Calls the native function directly */ |
||
352 | private static function _call($function, $args) |
||
356 | |||
357 | /* Shifts of the first argument (callable) and pushes it to the end */ |
||
358 | private static function _rotateRight($function, $args) |
||
364 | |||
365 | /* Swaps the first two args */ |
||
366 | private static function _swapTwoFirst($function, $args) |
||
374 | |||
375 | /* Makes a copy of the array and returns it after invoking function */ |
||
376 | private static function _copy($function, $args) |
||
382 | |||
383 | /* If multiple arrays are passed as arguments mulitple will be returned. Otherwise _copy is used */ |
||
384 | private static function _copyMultiple($function, $args) |
||
398 | |||
399 | /* Makes a copy of the array and returns it after invoking function */ |
||
400 | private static function _copyValue($function, $args, $object = null) |
||
409 | |||
410 | private static function _arrgh($function, $args) |
||
415 | |||
416 | private static function arr_map_assoc($array, Closure $callable) |
||
421 | |||
422 | /** |
||
423 | * Sort an array of associative arrays by key. It checks the first two values for type |
||
424 | * either sorts by number or using strcmp. If a key is missing entries are moved to the top |
||
425 | * (or bottom depending on $direction) |
||
426 | */ |
||
427 | private static function arr_sort_by($array, $key, $direction = "ASC") |
||
445 | |||
446 | private static function arr_collapse($array) |
||
456 | |||
457 | private static function arr_contains($array, $search, $key = null) |
||
469 | |||
470 | private static function arr_except($array, $except) |
||
491 | |||
492 | private static function arr_only($array, $only) |
||
515 | |||
516 | /** |
||
517 | * Get for multi-dimensional arrays |
||
518 | * |
||
519 | * @param array An array to query on |
||
520 | * @param path|array A string representing the path to traverse. |
||
521 | * Optionally pass as [ $path, ...$functions ] if `!$` is used |
||
522 | * @param bool Collapse resulting data-set |
||
523 | * @throws Exception Thrown when a path cannot be reached in case $array does |
||
524 | * not correspond to path type. E.g. collection expected |
||
525 | * but a simple value was encountered. |
||
526 | */ |
||
527 | private static function arr_get($array, $path, $collapse = false) |
||
536 | |||
537 | /* arr_get: Traverses path to get value */ |
||
538 | private static function _arr_get_traverse($data, $path, $collapse = false, $functions = []) |
||
634 | |||
635 | /* arr_get: Find next node by index */ |
||
636 | private static function _arr_get_traverse_next_node_index($data, $plug_index) |
||
650 | |||
651 | /* arr_get: Find next node by key */ |
||
652 | private static function _arr_get_traverse_next_node_key($data, $is_collection, $next_key) |
||
672 | |||
673 | /* arr_get: Invoke custom filter function on path */ |
||
674 | private static function _arr_get_traverse_apply_custom_function($data, $functions, $path) |
||
681 | |||
682 | private static function arr_is_collection($mixed) |
||
686 | |||
687 | /** |
||
688 | * Return the depth of a collection hiearchy. Zero based. |
||
689 | * |
||
690 | * @param array A collection |
||
691 | * @return int `null` if $array is not a collection. |
||
692 | */ |
||
693 | private static function arr_depth($array) |
||
706 | |||
707 | /** |
||
708 | * Partion the input based on the result of the callback function. |
||
709 | * |
||
710 | * @param array $array A collection |
||
711 | * @param \Closeure $callable A callable returning true or false depending on which way to partion the element—left or right. |
||
712 | * @return array An array with two arrays—left and right: [left, right] |
||
713 | */ |
||
714 | private static function arr_partition($array, Closure $callable) |
||
727 | |||
728 | private static function arr_even($array) |
||
732 | |||
733 | private static function arr_odd($array) |
||
737 | |||
738 | /* Synonym of shift */ |
||
739 | private static function arr_head($array) |
||
743 | |||
744 | private static function arr_first($array) |
||
751 | |||
752 | private static function arr_last($array) |
||
759 | |||
760 | private static function arr_tail($array) |
||
764 | |||
765 | // _arrgh |
||
766 | static private $arr_functions = [ |
||
767 | "collapse", |
||
768 | "contains", |
||
769 | "except", |
||
770 | "map_assoc", |
||
771 | "only", |
||
772 | "sort_by", |
||
773 | 'depth', |
||
774 | 'even', |
||
775 | 'first', |
||
776 | 'get', |
||
777 | 'head', |
||
778 | 'is_collection', |
||
779 | 'last', |
||
780 | 'odd', |
||
781 | 'partition', |
||
782 | 'tail', |
||
783 | ]; |
||
784 | |||
785 | // _call |
||
786 | static private $simple_functions = [ |
||
787 | "array_change_key_case", |
||
788 | "array_chunk", |
||
789 | "array_column", |
||
790 | "array_combine", |
||
791 | "array_count_values", |
||
792 | "array_diff", |
||
793 | "array_diff_assoc", |
||
794 | "array_diff_key", |
||
795 | "array_diff_uassoc", |
||
796 | "array_diff_ukey", |
||
797 | "array_fill", |
||
798 | "array_fill_keys", |
||
799 | "array_filter", |
||
800 | "array_flip", |
||
801 | "array_intersect", |
||
802 | "array_intersect_assoc", |
||
803 | "array_intersect_key", |
||
804 | "array_intersect_uassoc", |
||
805 | "array_intersect_ukey", |
||
806 | "array_keys", |
||
807 | "array_merge", |
||
808 | "array_merge_recursive", |
||
809 | "array_pad", |
||
810 | "array_product", |
||
811 | "array_rand", |
||
812 | "array_reduce", |
||
813 | "array_replace", |
||
814 | "array_replace_recursive", |
||
815 | "array_reverse", |
||
816 | "array_slice", |
||
817 | "array_sum", |
||
818 | "array_udiff", |
||
819 | "array_udiff_assoc", |
||
820 | "array_udiff_uassoc", |
||
821 | "array_uintersect", |
||
822 | "array_uintersect_assoc", |
||
823 | "array_uintersect_uassoc", |
||
824 | "array_unique", |
||
825 | "array_values", |
||
826 | "count", |
||
827 | "max", |
||
828 | "min", |
||
829 | "range", |
||
830 | "sizeof", |
||
831 | ]; |
||
832 | |||
833 | // _copy |
||
834 | static private $mutable_functions = [ |
||
835 | "array_push", |
||
836 | "array_splice", |
||
837 | "array_unshift", |
||
838 | "array_walk", |
||
839 | "array_walk_recursive", |
||
840 | "arsort", |
||
841 | "asort", |
||
842 | "krsort", |
||
843 | "ksort", |
||
844 | "natcasesort", |
||
845 | "natsort", |
||
846 | "rsort", |
||
847 | "shuffle", |
||
848 | "sort", |
||
849 | "uasort", |
||
850 | "uksort", |
||
851 | "usort", |
||
852 | ]; |
||
853 | |||
854 | // _copyMultiple |
||
855 | static private $mutable_functions_multiple = [ |
||
856 | "array_multisort", |
||
857 | ]; |
||
858 | |||
859 | // _copyValue |
||
860 | static private $mutable_value_functions = [ |
||
861 | "array_pop", |
||
862 | "array_shift", |
||
863 | "end", |
||
864 | ]; |
||
865 | |||
866 | // _rotateRight |
||
867 | static private $reverse_functions = [ |
||
868 | "array_map", |
||
869 | ]; |
||
870 | |||
871 | // _swapTwoFirst |
||
872 | static private $swapped_functions = [ |
||
873 | "array_key_exists", |
||
874 | "array_search", |
||
875 | "implode", |
||
876 | "in_array", |
||
877 | "join", |
||
878 | ]; |
||
879 | |||
880 | static private $starters = [ |
||
881 | "array_fill", |
||
882 | "array_fill_keys", |
||
883 | "range", |
||
884 | ]; |
||
885 | |||
886 | static private $terminators = [ |
||
887 | "array_pop", |
||
888 | "array_shift", |
||
889 | "array_sum", |
||
890 | "count", |
||
891 | "first", |
||
892 | "head", |
||
893 | "join", |
||
894 | "last", |
||
895 | "max", |
||
896 | "min", |
||
897 | "sizeof", |
||
898 | ]; |
||
899 | |||
900 | static private $reverse_result_functions = [ |
||
901 | "uasort", |
||
902 | "uksort", |
||
903 | "usort", |
||
904 | "asort", |
||
905 | ]; |
||
906 | } |
||
907 | |||
911 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.