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 Sensei_Main 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 Sensei_Main, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class Sensei_Main { |
||
12 | |||
13 | /** |
||
14 | * @var string |
||
15 | * Reference to the main plugin file |
||
16 | */ |
||
17 | private $file; |
||
18 | |||
19 | /** |
||
20 | * @var Sensei_Main $_instance to the the main and only instance of the Sensei class. |
||
21 | * @since 1.8.0 |
||
22 | */ |
||
23 | protected static $_instance = null; |
||
24 | |||
25 | /** |
||
26 | * Main reference to the plugins current version |
||
27 | */ |
||
28 | public $version; |
||
29 | |||
30 | /** |
||
31 | * Public token, referencing for the text domain. |
||
32 | */ |
||
33 | public $token = 'woothemes-sensei'; |
||
34 | |||
35 | /** |
||
36 | * Plugin url and path for use when access resources. |
||
37 | */ |
||
38 | public $plugin_url; |
||
39 | public $plugin_path; |
||
40 | public $template_url; |
||
41 | |||
42 | /** |
||
43 | * @var Sensei_PostTypes |
||
44 | * All Sensei sub classes. Currently used to access functionality contained within |
||
45 | * within Sensei sub classes e.g. Sensei()->course->all_courses() |
||
46 | */ |
||
47 | public $post_types; |
||
48 | |||
49 | /** |
||
50 | * @var WooThemes_Sensei_Settings |
||
51 | */ |
||
52 | public $settings; |
||
53 | |||
54 | /** |
||
55 | * @var WooThemes_Sensei_Course_Results |
||
56 | */ |
||
57 | public $course_results; |
||
58 | |||
59 | /** |
||
60 | * @var Sensei_Updates |
||
61 | */ |
||
62 | public $updates; |
||
63 | /** |
||
64 | * @var WooThemes_Sensei_Course |
||
65 | */ |
||
66 | public $course; |
||
67 | |||
68 | /** |
||
69 | * @var WooThemes_Sensei_Lesson |
||
70 | */ |
||
71 | public $lesson; |
||
72 | |||
73 | /** |
||
74 | * @var WooThemes_Sensei_Quiz |
||
75 | */ |
||
76 | public $quiz; |
||
77 | |||
78 | /** |
||
79 | * @var WooThemes_Sensei_Question |
||
80 | */ |
||
81 | public $question; |
||
82 | |||
83 | /** |
||
84 | * @var WooThemes_Sensei_Admin |
||
85 | */ |
||
86 | public $admin; |
||
87 | |||
88 | /** |
||
89 | * @var WooThemes_Sensei_Frontend |
||
90 | */ |
||
91 | public $frontend; |
||
92 | |||
93 | /** |
||
94 | * @var Sensei_Notices |
||
95 | */ |
||
96 | public $notices; |
||
97 | |||
98 | /** |
||
99 | * @var WooThemes_Sensei_Grading |
||
100 | */ |
||
101 | public $grading; |
||
102 | |||
103 | /** |
||
104 | * @var WooThemes_Sensei_Emails |
||
105 | */ |
||
106 | public $emails; |
||
107 | |||
108 | /** |
||
109 | * @var WooThemes_Sensei_Learner_Profiles |
||
110 | */ |
||
111 | public $learner_profiles; |
||
112 | |||
113 | /** |
||
114 | * @var Sensei_Teacher |
||
115 | */ |
||
116 | public $teacher; |
||
117 | |||
118 | /** |
||
119 | * @var WooThemes_Sensei_Learners |
||
120 | */ |
||
121 | public $learners; |
||
122 | |||
123 | /** |
||
124 | * @var array |
||
125 | * Global instance for access to the permissions message shown |
||
126 | * when users do not have the right privileges to access resources. |
||
127 | */ |
||
128 | public $permissions_message; |
||
129 | |||
130 | /** |
||
131 | * @var Sensei_Core_Modules Sensei Modules functionality |
||
132 | */ |
||
133 | public $modules; |
||
134 | |||
135 | /** |
||
136 | * @var Sensei_Analysis |
||
137 | */ |
||
138 | public $analysis; |
||
139 | |||
140 | /** |
||
141 | * Constructor method. |
||
142 | * @param string $file The base file of the plugin. |
||
143 | * @since 1.0.0 |
||
144 | */ |
||
145 | public function __construct ( $file ) { |
||
169 | |||
170 | /** |
||
171 | * Load the foundations of Sensei. |
||
172 | * @since 1.9.0 |
||
173 | */ |
||
174 | protected function init(){ |
||
188 | |||
189 | /** |
||
190 | * Global Sensei Instance |
||
191 | * |
||
192 | * Ensure that only one instance of the main Sensei class can be loaded. |
||
193 | * |
||
194 | * @since 1.8.0 |
||
195 | * @static |
||
196 | * @see WC() |
||
197 | * @return WooThemes_Sensei Instance. |
||
198 | */ |
||
199 | public static function instance() { |
||
216 | |||
217 | /** |
||
218 | * This function is linked into the activation |
||
219 | * hook to reset flush the urls to ensure Sensei post types show up. |
||
220 | * |
||
221 | * @since 1.9.0 |
||
222 | * |
||
223 | * @param $plugin |
||
224 | */ |
||
225 | public static function activation_flush_rules( $plugin ){ |
||
234 | |||
235 | /** |
||
236 | * Cloning is forbidden. |
||
237 | * @since 1.8.0 |
||
238 | */ |
||
239 | public function __clone() { |
||
242 | |||
243 | /** |
||
244 | * Unserializing instances of this class is forbidden. |
||
245 | * @since 1.8.0 |
||
246 | */ |
||
247 | public function __wakeup() { |
||
250 | |||
251 | /** |
||
252 | * Load the properties for the main Sensei object |
||
253 | * |
||
254 | * @since 1.9.0 |
||
255 | */ |
||
256 | public function initialize_global_objects(){ |
||
324 | |||
325 | /** |
||
326 | * Initialize all Sensei hooks |
||
327 | * |
||
328 | * @since 1.9.0 |
||
329 | */ |
||
330 | public function load_hooks(){ |
||
347 | |||
348 | /** |
||
349 | * Run Sensei updates. |
||
350 | * @access public |
||
351 | * @since 1.1.0 |
||
352 | * @return void |
||
353 | */ |
||
354 | public function run_updates() { |
||
362 | |||
363 | /** |
||
364 | * Register the widgets. |
||
365 | * @access public |
||
366 | * @since 1.0.0 |
||
367 | * @return void |
||
368 | */ |
||
369 | public function register_widgets () { |
||
386 | |||
387 | /** |
||
388 | * Load the plugin's localisation file. |
||
389 | * @access public |
||
390 | * @since 1.0.0 |
||
391 | * @return void |
||
392 | */ |
||
393 | public function load_localisation () { |
||
398 | |||
399 | /** |
||
400 | * Load the plugin textdomain from the main WordPress "languages" folder. |
||
401 | * @access public |
||
402 | * @since 1.0.0 |
||
403 | * @return void |
||
404 | */ |
||
405 | public function load_plugin_textdomain () { |
||
414 | |||
415 | /** |
||
416 | * Run on activation. |
||
417 | * @access public |
||
418 | * @since 1.0.0 |
||
419 | * @return void |
||
420 | */ |
||
421 | public function activation () { |
||
426 | |||
427 | |||
428 | /** |
||
429 | * Register activation hooks. |
||
430 | * @access public |
||
431 | * @since 1.0.0 |
||
432 | * @return void |
||
433 | */ |
||
434 | public function install () { |
||
440 | |||
441 | |||
442 | /** |
||
443 | * Run on activation of the plugin. |
||
444 | * @access public |
||
445 | * @since 1.0.0 |
||
446 | * @return void |
||
447 | */ |
||
448 | public function activate_sensei () { |
||
454 | |||
455 | /** |
||
456 | * Register the plugin's version. |
||
457 | * @access public |
||
458 | * @since 1.0.0 |
||
459 | * @return void |
||
460 | */ |
||
461 | private function register_plugin_version () { |
||
468 | |||
469 | /** |
||
470 | * Ensure that "post-thumbnails" support is available for those themes that don't register it. |
||
471 | * @access public |
||
472 | * @since 1.0.1 |
||
473 | * @return void |
||
474 | */ |
||
475 | public function ensure_post_thumbnails_support () { |
||
480 | |||
481 | /** |
||
482 | * template_loader function. |
||
483 | * |
||
484 | * @access public |
||
485 | * @param mixed $template |
||
486 | * @return void |
||
487 | * @deprecated |
||
488 | */ |
||
489 | public function template_loader ( $template = '' ) { |
||
495 | |||
496 | /** |
||
497 | * Determine the relative path to the plugin's directory. |
||
498 | * @access public |
||
499 | * @since 1.0.0 |
||
500 | * @return string $sensei_plugin_path |
||
501 | */ |
||
502 | public function plugin_path () { |
||
517 | |||
518 | /** |
||
519 | * Retrieve the ID of a specified page setting. |
||
520 | * @access public |
||
521 | * @since 1.0.0 |
||
522 | * @param string $page |
||
523 | * @return int |
||
524 | */ |
||
525 | public function get_page_id ( $page ) { |
||
529 | |||
530 | /** |
||
531 | * check_user_permissions function. |
||
532 | * |
||
533 | * @access public |
||
534 | * @param string $page (default: '') |
||
535 | * |
||
536 | * @return bool |
||
537 | */ |
||
538 | public function check_user_permissions ( $page = '' ) { |
||
711 | |||
712 | |||
713 | /** |
||
714 | * Check if visitors have access permission. If the "access_permission" setting is active, do a log in check. |
||
715 | * @since 1.0.0 |
||
716 | * @access public |
||
717 | * @return bool |
||
718 | */ |
||
719 | public function access_settings () { |
||
733 | |||
734 | /** |
||
735 | * load_class loads in class files |
||
736 | * @since 1.2.0 |
||
737 | * @access public |
||
738 | * @return void |
||
739 | */ |
||
740 | public function load_class ( $class_name = '' ) { |
||
745 | |||
746 | /** |
||
747 | * Filtering wp_count_comments to ensure that Sensei comments are ignored |
||
748 | * @since 1.4.0 |
||
749 | * @access public |
||
750 | * @param array $comments |
||
751 | * @param integer $post_id |
||
752 | * @return array |
||
753 | */ |
||
754 | public function sensei_count_comments( $comments, $post_id ) { |
||
800 | |||
801 | /** |
||
802 | * Init images. |
||
803 | * |
||
804 | * @since 1.4.5 |
||
805 | * @access public |
||
806 | * @return void |
||
807 | */ |
||
808 | public function init_image_sizes() { |
||
819 | |||
820 | /** |
||
821 | * Get an image size. |
||
822 | * |
||
823 | * Variable is filtered by sensei_get_image_size_{image_size} |
||
824 | * |
||
825 | * @since 1.4.5 |
||
826 | * @access public |
||
827 | * @param mixed $image_size |
||
828 | * @return string |
||
829 | */ |
||
830 | public function get_image_size( $image_size ) { |
||
858 | |||
859 | public function body_class( $classes ) { |
||
865 | |||
866 | /** |
||
867 | * Checks that the Jetpack Beautiful Maths module has been activated to support LaTeX within question titles and answers |
||
868 | * |
||
869 | * @return null |
||
870 | * @since 1.7.0 |
||
871 | */ |
||
872 | public function jetpack_latex_support() { |
||
878 | |||
879 | /** |
||
880 | * Load the module functionality. |
||
881 | * |
||
882 | * This function is hooked into plugins_loaded to avoid conflicts with |
||
883 | * the retired modules extension. |
||
884 | * |
||
885 | * @since 1.8.0 |
||
886 | */ |
||
887 | public function load_modules_class(){ |
||
904 | |||
905 | /** |
||
906 | * Tell the user to that the modules extension is no longer needed. |
||
907 | * |
||
908 | * @since 1.8.0 |
||
909 | */ |
||
910 | public function disable_sensei_modules_extension(){ ?> |
||
923 | |||
924 | /** |
||
925 | * Sensei wide rewrite flush call. |
||
926 | * |
||
927 | * To use this simply update the option 'sensei_flush_rewrite_rules' to 1 |
||
928 | * |
||
929 | * After the option is one the Rules will be flushed. |
||
930 | * |
||
931 | * @since 1.9.0 |
||
932 | */ |
||
933 | public function flush_rewrite_rules(){ |
||
952 | |||
953 | /** |
||
954 | * Calling this function will tell Sensei to flush rewrite |
||
955 | * rules on the next load. |
||
956 | * |
||
957 | * @since 1.9.0 |
||
958 | */ |
||
959 | public function initiate_rewrite_rules_flush(){ |
||
964 | |||
965 | /** |
||
966 | * sensei_woocommerce_email_course_details adds detail to email |
||
967 | * |
||
968 | * @deprecated since 1.9.0 use Sensei_WC::email_course_details |
||
969 | * |
||
970 | * @since 1.4.5 |
||
971 | * @access public |
||
972 | * @param WC_Order $order |
||
973 | * |
||
974 | * @return void |
||
975 | */ |
||
976 | public function sensei_woocommerce_email_course_details( $order ) { |
||
981 | |||
982 | /** |
||
983 | * @deprecated since 1.9.0, movde to the Sensei_WC class |
||
984 | * @param $user_id |
||
985 | * @param $subscription_key |
||
986 | */ |
||
987 | public function sensei_woocommerce_reactivate_subscription( $user_id, $subscription_key ){ |
||
991 | |||
992 | /** |
||
993 | * @deprecated since 1.9.0, movde to the Sensei_WC class |
||
994 | * @param $user_id |
||
995 | * @param $subscription_key |
||
996 | */ |
||
997 | public function sensei_woocommerce_subscription_ended( $user_id, $subscription_key ){ |
||
1001 | |||
1002 | /** |
||
1003 | * sensei_woocommerce_complete_order description |
||
1004 | * |
||
1005 | * @deprecated since 1.9.0 use Sensei_WC::complete_order( $order_id ); |
||
1006 | * @since 1.0.3 |
||
1007 | * @access public |
||
1008 | * @param int $order_id WC order ID |
||
1009 | * |
||
1010 | * @return void |
||
1011 | */ |
||
1012 | public function sensei_woocommerce_complete_order ( $order_id = 0 ) { |
||
1017 | |||
1018 | /** |
||
1019 | * Runs when an order is cancelled. |
||
1020 | * |
||
1021 | * @deprecated since 1.9.0 |
||
1022 | * |
||
1023 | * @since 1.2.0 |
||
1024 | * @param integer $order_id order ID |
||
1025 | * @return void |
||
1026 | */ |
||
1027 | public function sensei_woocommerce_cancel_order ( $order_id ) { |
||
1032 | |||
1033 | /** |
||
1034 | * sensei_activate_subscription runs when a subscription product is purchased |
||
1035 | * @deprecated since 1.9.0 |
||
1036 | * @since 1.2.0 |
||
1037 | * @access public |
||
1038 | * @param integer $order_id order ID |
||
1039 | * @return void |
||
1040 | */ |
||
1041 | public function sensei_activate_subscription( $order_id = 0 ) { |
||
1046 | |||
1047 | /** |
||
1048 | * If WooCommerce is activated and the customer has purchased the course, update Sensei to indicate that they are taking the course. |
||
1049 | * @deprecated since 1.9.0 |
||
1050 | * @since 1.0.0 |
||
1051 | * @param int $course_id (default: 0) |
||
1052 | * @param array/Object $order_user (default: array()) Specific user's data. |
||
1053 | * @return bool|int |
||
1054 | */ |
||
1055 | public function woocommerce_course_update ( $course_id = 0, $order_user = array() ) { |
||
1060 | |||
1061 | /** |
||
1062 | * Returns the WooCommerce Product Object |
||
1063 | * |
||
1064 | * The code caters for pre and post WooCommerce 2.2 installations. |
||
1065 | * |
||
1066 | * @deprecated since 1.9.0 |
||
1067 | * @since 1.1.1 |
||
1068 | * |
||
1069 | * @param integer $wc_product_id Product ID or Variation ID |
||
1070 | * @param string $product_type '' or 'variation' |
||
1071 | * |
||
1072 | * @return WC_Product $wc_product_object |
||
1073 | */ |
||
1074 | public function sensei_get_woocommerce_product_object ( $wc_product_id = 0, $product_type = '' ) { |
||
1079 | |||
1080 | /** |
||
1081 | * Setup required WooCommerce settings. |
||
1082 | * @access public |
||
1083 | * @since 1.1.0 |
||
1084 | * @return void |
||
1085 | */ |
||
1086 | public function set_woocommerce_functionality() { |
||
1091 | |||
1092 | /** |
||
1093 | * Disable guest checkout if a course product is in the cart |
||
1094 | * @deprecated since 1.9.0 |
||
1095 | * @param boolean $guest_checkout Current guest checkout setting |
||
1096 | * @return boolean Modified guest checkout setting |
||
1097 | */ |
||
1098 | public function disable_guest_checkout( $guest_checkout ) { |
||
1103 | |||
1104 | /** |
||
1105 | * Change order status with virtual products to completed |
||
1106 | * |
||
1107 | * @deprecated since 1.9.0 use Sensei_WC::virtual_order_payment_complete( $order_status, $order_id ) |
||
1108 | * |
||
1109 | * @since 1.1.0 |
||
1110 | * @param string $order_status |
||
1111 | * @param int $order_id |
||
1112 | * @return string |
||
1113 | **/ |
||
1114 | public function virtual_order_payment_complete( $order_status, $order_id ) { |
||
1118 | |||
1119 | } // End Class |
||
1120 | |||
1127 |
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.