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 Hooks 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 Hooks, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
35 | class Hooks |
||
36 | { |
||
37 | /** |
||
38 | * Filters - holds list of hooks |
||
39 | * |
||
40 | * @var array |
||
41 | * @access protected |
||
42 | * @since 1.0.0 |
||
43 | */ |
||
44 | protected $filters = array(); |
||
45 | |||
46 | /** |
||
47 | * Merged Filters |
||
48 | * |
||
49 | * @var array |
||
50 | * @access protected |
||
51 | * @since 1.0.0 |
||
52 | */ |
||
53 | protected $merged_filters = array(); |
||
54 | |||
55 | /** |
||
56 | * Actions |
||
57 | * |
||
58 | * @var array |
||
59 | * @access protected |
||
60 | * @since 1.0.0 |
||
61 | */ |
||
62 | protected $actions = array(); |
||
63 | |||
64 | /** |
||
65 | * Current Filter - holds the name of the current filter |
||
66 | * |
||
67 | * @var array |
||
68 | * @access protected |
||
69 | * @since 1.0.0 |
||
70 | */ |
||
71 | protected $current_filter = array(); |
||
72 | |||
73 | /** |
||
74 | * Container for storing shortcode tags and their hook to call for the shortcode |
||
75 | * |
||
76 | * @since 1.0.0 |
||
77 | * @name $shortcode_tags |
||
78 | * @var array |
||
79 | */ |
||
80 | public static $shortcode_tags = array(); |
||
81 | |||
82 | /** |
||
83 | * Default priority |
||
84 | * |
||
85 | * @since 0.2 |
||
86 | * @const int |
||
87 | */ |
||
88 | const PRIORITY_NEUTRAL = 50; |
||
89 | |||
90 | /** |
||
91 | * is not allowed to call from outside: private! |
||
92 | * |
||
93 | * @access private |
||
94 | */ |
||
95 | 1 | protected function __construct() |
|
98 | |||
99 | /** |
||
100 | * prevent the instance from being cloned |
||
101 | * |
||
102 | * @access private |
||
103 | * |
||
104 | * @return void |
||
105 | */ |
||
106 | protected function __clone() |
||
109 | |||
110 | /** |
||
111 | * Singleton Instance |
||
112 | * |
||
113 | * Returns a Singleton instance of this class. |
||
114 | * |
||
115 | * @param void |
||
116 | * |
||
117 | * @return Hooks |
||
118 | * @access public |
||
119 | * @static |
||
120 | * @since 1.0.0 |
||
121 | */ |
||
122 | 9 | public static function getInstance() |
|
132 | |||
133 | /** |
||
134 | * FILTERS |
||
135 | */ |
||
136 | |||
137 | /** |
||
138 | * Adds Hooks to a function or method to a specific filter action. |
||
139 | * |
||
140 | * @access public |
||
141 | * @since 1.0.0 |
||
142 | * |
||
143 | * @param string $tag The name of the filter to hook the |
||
144 | * {@link $function_to_add} to. |
||
145 | * @param string $function_to_add The name of the function to be called |
||
146 | * when the filter is applied. |
||
147 | * @param integer $priority (optional) Used to specify the order in |
||
148 | * which the functions associated with a |
||
149 | * particular action are executed (default: 50). |
||
150 | * Lower numbers correspond with earlier execution, |
||
151 | * and functions with the same priority are executed |
||
152 | * in the order in which they were added to the action. |
||
153 | * @param string $include_path optional. File to include before executing the callback. |
||
154 | * |
||
155 | * @return boolean true |
||
156 | */ |
||
157 | 7 | public function add_filter($tag, $function_to_add, $priority = self::PRIORITY_NEUTRAL, $include_path = null) |
|
170 | |||
171 | /** |
||
172 | * Removes a function from a specified filter hook. |
||
173 | * |
||
174 | * @param string $tag the filter hook to which the function to be removed is hooked. |
||
175 | * @param mixed $function_to_remove the name of the function which should be removed. |
||
176 | * @param int $priority (optional) The priority of the function (default: 50). |
||
177 | * |
||
178 | * @return bool |
||
179 | */ |
||
180 | 1 | public function remove_filter($tag, $function_to_remove, $priority = self::PRIORITY_NEUTRAL) |
|
197 | |||
198 | /** |
||
199 | * Remove all of the hooks from a filter. |
||
200 | * |
||
201 | * @param string $tag the filter to remove hooks from. |
||
202 | * @param bool $priority the priority number to remove. |
||
203 | * |
||
204 | * @return bool True when finished. |
||
205 | */ |
||
206 | 4 | public function remove_all_filters($tag, $priority = false) |
|
224 | |||
225 | /** |
||
226 | * Check if any filter has been registered for the given hook. |
||
227 | * |
||
228 | * Info: Use !== false to check if it's true! |
||
229 | * |
||
230 | * @param string $tag the name of the filter hook. |
||
231 | * @param bool $function_to_check callback function name to check for. [optional] |
||
232 | * |
||
233 | * @return mixed If {@link $function_to_check} is omitted, |
||
234 | * returns boolean for whether the hook has |
||
235 | * anything registered. |
||
236 | * When checking a specific function, the priority |
||
237 | * of that hook is returned, or false if the |
||
238 | * function is not attached. |
||
239 | * When using the {@link $function_to_check} argument, |
||
240 | * this function may return a non-boolean value that |
||
241 | * evaluates to false |
||
242 | * (e.g.) 0, so use the === operator for testing the return value. |
||
243 | * @access public |
||
244 | * @since 1.0.0 |
||
245 | */ |
||
246 | 3 | public function has_filter($tag, $function_to_check = false) |
|
265 | |||
266 | /** |
||
267 | * Call the functions added to a filter hook. |
||
268 | * |
||
269 | * Info: Additional variables passed to the functions hooked to <tt>$tag</tt>. |
||
270 | * |
||
271 | * @param string $tag The name of the filter hook. |
||
272 | * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on. |
||
273 | * |
||
274 | * @return mixed The filtered value after all hooked functions are applied to it. |
||
275 | * @access public |
||
276 | * @since 1.0.0 |
||
277 | */ |
||
278 | 4 | public function apply_filters($tag, $value) |
|
334 | |||
335 | /** |
||
336 | * Execute functions hooked on a specific filter hook, specifying arguments in an array. |
||
337 | * |
||
338 | * @param string $tag The name of the filter hook. |
||
339 | * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt> |
||
340 | * |
||
341 | * @return mixed The filtered value after all hooked functions are applied to it. |
||
342 | * |
||
343 | * @access public |
||
344 | * @since 1.0.0 |
||
345 | */ |
||
346 | 1 | public function apply_filters_ref_array($tag, $args) |
|
393 | |||
394 | /** |
||
395 | * ACTIONS |
||
396 | */ |
||
397 | |||
398 | /** |
||
399 | * Hooks a function on to a specific action. |
||
400 | * |
||
401 | * @param string $tag The name of the action to which the |
||
402 | * <tt>$function_to_add</tt> is hooked. |
||
403 | * @param string $function_to_add The name of the function you wish to be called. |
||
404 | * @param integer $priority (optional) Used to specify the order in which |
||
405 | * the functions associated with a particular |
||
406 | * action are executed (default: 50). |
||
407 | * Lower numbers correspond with earlier execution, |
||
408 | * and functions with the same priority are executed |
||
409 | * in the order in which they were added to the action. |
||
410 | * @param string $include_path optional. File to include before executing the callback. |
||
411 | * |
||
412 | * @access public |
||
413 | * @since 1.0.0 |
||
414 | * @return bool |
||
415 | */ |
||
416 | 5 | public function add_action($tag, $function_to_add, $priority = self::PRIORITY_NEUTRAL, $include_path = null) |
|
420 | |||
421 | /** |
||
422 | * Check if any action has been registered for a hook. |
||
423 | * |
||
424 | * Info: Use !== false to check if it's true! |
||
425 | * |
||
426 | * @param string $tag The name of the action hook. |
||
427 | * @param bool|string $function_to_check (optional) |
||
428 | * |
||
429 | * @return mixed If <tt>$function_to_check</tt> is omitted, |
||
430 | * returns boolean for whether the hook has |
||
431 | * anything registered. |
||
432 | * When checking a specific function, |
||
433 | * the priority of that hook is returned, |
||
434 | * or false if the function is not attached. |
||
435 | * When using the <tt>$function_to_check</tt> |
||
436 | * argument, this function may return a non-boolean |
||
437 | * value that evaluates to false (e.g.) 0, |
||
438 | * so use the === operator for testing the return value. |
||
439 | * @access public |
||
440 | * @since 1.0.0 |
||
441 | */ |
||
442 | 3 | public function has_action($tag, $function_to_check = false) |
|
446 | |||
447 | /** |
||
448 | * Removes a function from a specified action hook. |
||
449 | * |
||
450 | * @param string $tag the action hook to which the function to be removed is hooked. |
||
451 | * @param mixed $function_to_remove the name of the function which should be removed. |
||
452 | * @param int $priority [optional] The priority of the function (default: 50). |
||
453 | * |
||
454 | * @return bool Whether the function is removed. |
||
455 | */ |
||
456 | 1 | public function remove_action($tag, $function_to_remove, $priority = self::PRIORITY_NEUTRAL) |
|
460 | |||
461 | /** |
||
462 | * Remove all of the hooks from an action. |
||
463 | * |
||
464 | * @param string $tag the action to remove hooks from. |
||
465 | * @param bool $priority the priority number to remove them from. |
||
466 | * |
||
467 | * @return bool True when finished. |
||
468 | */ |
||
469 | 4 | public function remove_all_actions($tag, $priority = false) |
|
473 | |||
474 | /** |
||
475 | * Execute functions hooked on a specific action hook. |
||
476 | * |
||
477 | * @param string $tag The name of the action to be executed. |
||
478 | * @param mixed $arg ,.. Optional additional arguments which are passed on |
||
479 | * to the functions hooked to the action. |
||
480 | * |
||
481 | * @return bool Will return false if $tag does not exist in $filter array |
||
482 | * @access public |
||
483 | * @since 1.0.0 |
||
484 | */ |
||
485 | 2 | public function do_action($tag, $arg = '') |
|
564 | |||
565 | /** |
||
566 | * Execute functions hooked on a specific action hook, specifying arguments in an array. |
||
567 | * |
||
568 | * @param string $tag The name of the action to be executed. |
||
569 | * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt> |
||
570 | * |
||
571 | * @return bool Will return false if $tag does not exist in $filter array |
||
572 | * @access public |
||
573 | * @since 1.0.0 |
||
574 | */ |
||
575 | 1 | public function do_action_ref_array($tag, $args) |
|
632 | |||
633 | /** |
||
634 | * Retrieve the number of times an action has fired. |
||
635 | * |
||
636 | * @param string $tag The name of the action hook. |
||
637 | * |
||
638 | * @return integer The number of times action hook <tt>$tag</tt> is fired |
||
639 | * @access public |
||
640 | * @since 1.0.0 |
||
641 | */ |
||
642 | 1 | public function did_action($tag) |
|
643 | { |
||
644 | 1 | if (!is_array($this->actions) || !isset($this->actions[$tag])) { |
|
645 | return 0; |
||
646 | } |
||
647 | |||
648 | 1 | return $this->actions[$tag]; |
|
649 | } |
||
650 | |||
651 | /** |
||
652 | * HELPERS |
||
653 | */ |
||
654 | |||
655 | /** |
||
656 | * Retrieve the name of the current filter or action. |
||
657 | * |
||
658 | * @param void |
||
659 | * |
||
660 | * @return string Hook name of the current filter or action. |
||
661 | * @access public |
||
662 | * @since 1.0.0 |
||
663 | */ |
||
664 | public function current_filter() |
||
668 | |||
669 | /** |
||
670 | * Build Unique ID for storage and retrieval. |
||
671 | * |
||
672 | * @param string $function Used for creating unique id |
||
673 | * |
||
674 | * @return string|bool Unique ID for usage as array key or false if |
||
675 | * $priority === false and $function is an |
||
676 | * object reference, and it does not already have a unique id. |
||
677 | * @access private |
||
678 | * @since 1.0.0 |
||
679 | */ |
||
680 | 7 | private function __filter_build_unique_id($function) |
|
706 | |||
707 | /** |
||
708 | * Call "All" Hook |
||
709 | * |
||
710 | * @param array $args |
||
711 | * |
||
712 | * @access public |
||
713 | * @since 1.0.0 |
||
714 | */ |
||
715 | 1 | public function __call_all_hook($args) |
|
733 | |||
734 | /** |
||
735 | * Add hook for shortcode tag. |
||
736 | * |
||
737 | * There can only be one hook for each shortcode. Which means that if another |
||
738 | * plugin has a similar shortcode, it will override yours or yours will override |
||
739 | * theirs depending on which order the plugins are included and/or ran. |
||
740 | * |
||
741 | * Simplest example of a shortcode tag using the API: |
||
742 | * |
||
743 | * <code> |
||
744 | * // [footag foo="bar"] |
||
745 | * function footag_func($atts) { |
||
746 | * return "foo = {$atts[foo]}"; |
||
747 | * } |
||
748 | * add_shortcode('footag', 'footag_func'); |
||
749 | * </code> |
||
750 | * |
||
751 | * Example with nice attribute defaults: |
||
752 | * |
||
753 | * <code> |
||
754 | * // [bartag foo="bar"] |
||
755 | * function bartag_func($atts) { |
||
756 | * $args = shortcode_atts(array( |
||
757 | * 'foo' => 'no foo', |
||
758 | * 'baz' => 'default baz', |
||
759 | * ), $atts); |
||
760 | * |
||
761 | * return "foo = {$args['foo']}"; |
||
762 | * } |
||
763 | * add_shortcode('bartag', 'bartag_func'); |
||
764 | * </code> |
||
765 | * |
||
766 | * Example with enclosed content: |
||
767 | * |
||
768 | * <code> |
||
769 | * // [baztag]content[/baztag] |
||
770 | * function baztag_func($atts, $content='') { |
||
771 | * return "content = $content"; |
||
772 | * } |
||
773 | * add_shortcode('baztag', 'baztag_func'); |
||
774 | * </code> |
||
775 | * |
||
776 | * @since 1.0.0 |
||
777 | * |
||
778 | * @param string $tag Shortcode tag to be searched in post content. |
||
779 | * @param callable $func Hook to run when shortcode is found. |
||
780 | */ |
||
781 | 1 | public function add_shortcode($tag, $func) |
|
787 | |||
788 | /** |
||
789 | * Removes hook for shortcode. |
||
790 | * |
||
791 | * @since 1.0.0 |
||
792 | * |
||
793 | * @param string $tag shortcode tag to remove hook for. |
||
794 | */ |
||
795 | public function remove_shortcode($tag) |
||
799 | |||
800 | /** |
||
801 | * This function is simple, it clears all of the shortcode tags by replacing the |
||
802 | * shortcodes by a empty array. This is actually a very efficient method |
||
803 | * for removing all shortcodes. |
||
804 | * |
||
805 | * @since 1.0.0 |
||
806 | */ |
||
807 | public function remove_all_shortcodes() |
||
811 | |||
812 | /** |
||
813 | * Whether a registered shortcode exists named $tag |
||
814 | * |
||
815 | * @since 1.0.0 |
||
816 | * |
||
817 | * @param string $tag |
||
818 | * |
||
819 | * @return boolean |
||
820 | */ |
||
821 | public function shortcode_exists($tag) |
||
825 | |||
826 | /** |
||
827 | * Whether the passed content contains the specified shortcode |
||
828 | * |
||
829 | * @since 1.0.0 |
||
830 | * |
||
831 | * @param $content |
||
832 | * @param $tag |
||
833 | * |
||
834 | * @return bool |
||
835 | */ |
||
836 | public function has_shortcode($content, $tag) |
||
859 | |||
860 | /** |
||
861 | * Search content for shortcodes and filter shortcodes through their hooks. |
||
862 | * |
||
863 | * If there are no shortcode tags defined, then the content will be returned |
||
864 | * without any filtering. This might cause issues when plugins are disabled but |
||
865 | * the shortcode will still show up in the post or content. |
||
866 | * |
||
867 | * @since 1.0.0 |
||
868 | * |
||
869 | * @param string $content Content to search for shortcodes |
||
870 | * |
||
871 | * @return string Content with shortcodes filtered out. |
||
872 | */ |
||
873 | 1 | View Code Duplication | public function do_shortcode($content) |
890 | |||
891 | /** |
||
892 | * Retrieve the shortcode regular expression for searching. |
||
893 | * |
||
894 | * The regular expression combines the shortcode tags in the regular expression |
||
895 | * in a regex class. |
||
896 | * |
||
897 | * The regular expression contains 6 different sub matches to help with parsing. |
||
898 | * |
||
899 | * 1 - An extra [ to allow for escaping shortcodes with double [[]] |
||
900 | * 2 - The shortcode name |
||
901 | * 3 - The shortcode argument list |
||
902 | * 4 - The self closing / |
||
903 | * 5 - The content of a shortcode when it wraps some content. |
||
904 | * 6 - An extra ] to allow for escaping shortcodes with double [[]] |
||
905 | * |
||
906 | * @since 1.0.0 |
||
907 | * |
||
908 | * @return string The shortcode search regular expression |
||
909 | */ |
||
910 | 1 | public function get_shortcode_regex() |
|
947 | |||
948 | /** |
||
949 | * Regular Expression callable for do_shortcode() for calling shortcode hook. |
||
950 | * |
||
951 | * @see get_shortcode_regex for details of the match array contents. |
||
952 | * |
||
953 | * @since 1.0.0 |
||
954 | * @access private |
||
955 | * |
||
956 | * @param array $m Regular expression match array |
||
957 | * |
||
958 | * @return mixed False on failure. |
||
959 | */ |
||
960 | 1 | private function __do_shortcode_tag($m) |
|
978 | |||
979 | /** |
||
980 | * Retrieve all attributes from the shortcodes tag. |
||
981 | * |
||
982 | * The attributes list has the attribute name as the key and the value of the |
||
983 | * attribute as the value in the key/value pair. This allows for easier |
||
984 | * retrieval of the attributes, since all attributes have to be known. |
||
985 | * |
||
986 | * @since 1.0.0 |
||
987 | * |
||
988 | * @param string $text |
||
989 | * |
||
990 | * @return array List of attributes and their value. |
||
991 | */ |
||
992 | 1 | public function shortcode_parse_atts($text) |
|
1017 | |||
1018 | /** |
||
1019 | * Combine user attributes with known attributes and fill in defaults when needed. |
||
1020 | * |
||
1021 | * The pairs should be considered to be all of the attributes which are |
||
1022 | * supported by the caller and given as a list. The returned attributes will |
||
1023 | * only contain the attributes in the $pairs list. |
||
1024 | * |
||
1025 | * If the $atts list has unsupported attributes, then they will be ignored and |
||
1026 | * removed from the final returned list. |
||
1027 | * |
||
1028 | * @since 1.0.0 |
||
1029 | * |
||
1030 | * @param array $pairs Entire list of supported attributes and their defaults. |
||
1031 | * @param array $atts User defined attributes in shortcode tag. |
||
1032 | * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering |
||
1033 | * |
||
1034 | * @return array Combined and filtered attribute list. |
||
1035 | */ |
||
1036 | 1 | public function shortcode_atts($pairs, $atts, $shortcode = '') |
|
1070 | |||
1071 | /** |
||
1072 | * Remove all shortcode tags from the given content. |
||
1073 | * |
||
1074 | * @since 1.0.0 |
||
1075 | * |
||
1076 | * @param string $content Content to remove shortcode tags. |
||
1077 | * |
||
1078 | * @return string Content without shortcode tags. |
||
1079 | */ |
||
1080 | View Code Duplication | public function strip_shortcodes($content) |
|
1098 | |||
1099 | /** |
||
1100 | * Strip shortcode by tag. |
||
1101 | * |
||
1102 | * @access private |
||
1103 | * |
||
1104 | * @param $m |
||
1105 | * |
||
1106 | * @return string |
||
1107 | */ |
||
1108 | private function __strip_shortcode_tag($m) |
||
1117 | |||
1118 | } |
||
1119 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: