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 | 10 | 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 | * @return bool |
||
782 | */ |
||
783 | 2 | public function add_shortcode($tag, $func) |
|
793 | |||
794 | /** |
||
795 | * Removes hook for shortcode. |
||
796 | * |
||
797 | * @since 1.0.0 |
||
798 | * |
||
799 | * @param string $tag shortcode tag to remove hook for. |
||
800 | * |
||
801 | * @return bool |
||
802 | */ |
||
803 | 1 | public function remove_shortcode($tag) |
|
813 | |||
814 | /** |
||
815 | * This function is simple, it clears all of the shortcode tags by replacing the |
||
816 | * shortcodes by a empty array. This is actually a very efficient method |
||
817 | * for removing all shortcodes. |
||
818 | * |
||
819 | * @since 1.0.0 |
||
820 | * |
||
821 | * @return bool |
||
822 | */ |
||
823 | 1 | public function remove_all_shortcodes() |
|
829 | |||
830 | /** |
||
831 | * Whether a registered shortcode exists named $tag |
||
832 | * |
||
833 | * @since 1.0.0 |
||
834 | * |
||
835 | * @param string $tag |
||
836 | * |
||
837 | * @return boolean |
||
838 | */ |
||
839 | 1 | public function shortcode_exists($tag) |
|
843 | |||
844 | /** |
||
845 | * Whether the passed content contains the specified shortcode |
||
846 | * |
||
847 | * @since 1.0.0 |
||
848 | * |
||
849 | * @param $content |
||
850 | * @param $tag |
||
851 | * |
||
852 | * @return bool |
||
853 | */ |
||
854 | public function has_shortcode($content, $tag) |
||
877 | |||
878 | /** |
||
879 | * Search content for shortcodes and filter shortcodes through their hooks. |
||
880 | * |
||
881 | * If there are no shortcode tags defined, then the content will be returned |
||
882 | * without any filtering. This might cause issues when plugins are disabled but |
||
883 | * the shortcode will still show up in the post or content. |
||
884 | * |
||
885 | * @since 1.0.0 |
||
886 | * |
||
887 | * @param string $content Content to search for shortcodes |
||
888 | * |
||
889 | * @return string Content with shortcodes filtered out. |
||
890 | */ |
||
891 | 2 | View Code Duplication | public function do_shortcode($content) |
908 | |||
909 | /** |
||
910 | * Retrieve the shortcode regular expression for searching. |
||
911 | * |
||
912 | * The regular expression combines the shortcode tags in the regular expression |
||
913 | * in a regex class. |
||
914 | * |
||
915 | * The regular expression contains 6 different sub matches to help with parsing. |
||
916 | * |
||
917 | * 1 - An extra [ to allow for escaping shortcodes with double [[]] |
||
918 | * 2 - The shortcode name |
||
919 | * 3 - The shortcode argument list |
||
920 | * 4 - The self closing / |
||
921 | * 5 - The content of a shortcode when it wraps some content. |
||
922 | * 6 - An extra ] to allow for escaping shortcodes with double [[]] |
||
923 | * |
||
924 | * @since 1.0.0 |
||
925 | * |
||
926 | * @return string The shortcode search regular expression |
||
927 | */ |
||
928 | 2 | public function get_shortcode_regex() |
|
965 | |||
966 | /** |
||
967 | * Regular Expression callable for do_shortcode() for calling shortcode hook. |
||
968 | * |
||
969 | * @see get_shortcode_regex for details of the match array contents. |
||
970 | * |
||
971 | * @since 1.0.0 |
||
972 | * @access private |
||
973 | * |
||
974 | * @param array $m Regular expression match array |
||
975 | * |
||
976 | * @return mixed False on failure. |
||
977 | */ |
||
978 | 2 | private function __do_shortcode_tag($m) |
|
996 | |||
997 | /** |
||
998 | * Retrieve all attributes from the shortcodes tag. |
||
999 | * |
||
1000 | * The attributes list has the attribute name as the key and the value of the |
||
1001 | * attribute as the value in the key/value pair. This allows for easier |
||
1002 | * retrieval of the attributes, since all attributes have to be known. |
||
1003 | * |
||
1004 | * @since 1.0.0 |
||
1005 | * |
||
1006 | * @param string $text |
||
1007 | * |
||
1008 | * @return array List of attributes and their value. |
||
1009 | */ |
||
1010 | 2 | public function shortcode_parse_atts($text) |
|
1035 | |||
1036 | /** |
||
1037 | * Combine user attributes with known attributes and fill in defaults when needed. |
||
1038 | * |
||
1039 | * The pairs should be considered to be all of the attributes which are |
||
1040 | * supported by the caller and given as a list. The returned attributes will |
||
1041 | * only contain the attributes in the $pairs list. |
||
1042 | * |
||
1043 | * If the $atts list has unsupported attributes, then they will be ignored and |
||
1044 | * removed from the final returned list. |
||
1045 | * |
||
1046 | * @since 1.0.0 |
||
1047 | * |
||
1048 | * @param array $pairs Entire list of supported attributes and their defaults. |
||
1049 | * @param array $atts User defined attributes in shortcode tag. |
||
1050 | * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering |
||
1051 | * |
||
1052 | * @return array Combined and filtered attribute list. |
||
1053 | */ |
||
1054 | 2 | public function shortcode_atts($pairs, $atts, $shortcode = '') |
|
1088 | |||
1089 | /** |
||
1090 | * Remove all shortcode tags from the given content. |
||
1091 | * |
||
1092 | * @since 1.0.0 |
||
1093 | * |
||
1094 | * @param string $content Content to remove shortcode tags. |
||
1095 | * |
||
1096 | * @return string Content without shortcode tags. |
||
1097 | */ |
||
1098 | 1 | View Code Duplication | public function strip_shortcodes($content) |
1116 | |||
1117 | /** |
||
1118 | * Strip shortcode by tag. |
||
1119 | * |
||
1120 | * @access private |
||
1121 | * |
||
1122 | * @param $m |
||
1123 | * |
||
1124 | * @return string |
||
1125 | */ |
||
1126 | 1 | private function __strip_shortcode_tag($m) |
|
1135 | |||
1136 | } |
||
1137 |
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: