Complex classes like FS_Options 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 FS_Options, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class FS_Options { |
||
19 | /** |
||
20 | * @var string |
||
21 | */ |
||
22 | private $_id; |
||
23 | |||
24 | /** |
||
25 | * @var array[string]FS_Options { |
||
26 | * @key string |
||
27 | * @value FS_Options |
||
28 | * } |
||
29 | */ |
||
30 | private static $_instances; |
||
31 | |||
32 | /** |
||
33 | * @var FS_Option_Manager Site level options. |
||
34 | */ |
||
35 | private $_options; |
||
36 | |||
37 | /** |
||
38 | * @var FS_Option_Manager Network level options. |
||
39 | */ |
||
40 | private $_network_options; |
||
41 | |||
42 | /** |
||
43 | * @var int The ID of the blog that is associated with the current site level options. |
||
44 | */ |
||
45 | private $_blog_id = 0; |
||
46 | |||
47 | /** |
||
48 | * @var bool |
||
49 | */ |
||
50 | private $_is_multisite; |
||
51 | |||
52 | /** |
||
53 | * @var string[] Lazy collection of params on the site level. |
||
54 | */ |
||
55 | private static $_SITE_OPTIONS_MAP; |
||
56 | |||
57 | /** |
||
58 | * @author Leo Fajardo (@leorw) |
||
59 | * @since 2.0.0 |
||
60 | * |
||
61 | * @param string $id |
||
62 | * @param bool $load |
||
63 | * |
||
64 | * @return FS_Options |
||
65 | */ |
||
66 | static function instance( $id, $load = false ) { |
||
73 | |||
74 | /** |
||
75 | * @author Leo Fajardo (@leorw) |
||
76 | * @since 2.0.0 |
||
77 | * |
||
78 | * @param string $id |
||
79 | * @param bool $load |
||
80 | */ |
||
81 | private function __construct( $id, $load = false ) { |
||
92 | |||
93 | /** |
||
94 | * Switch the context of the site level options manager. |
||
95 | * |
||
96 | * @author Vova Feldman (@svovaf) |
||
97 | * @since 2.0.0 |
||
98 | * |
||
99 | * @param $blog_id |
||
100 | */ |
||
101 | function set_site_blog_context( $blog_id ) { |
||
106 | |||
107 | /** |
||
108 | * @author Leo Fajardo (@leorw) |
||
109 | * |
||
110 | * @param string $option |
||
111 | * @param mixed $default |
||
112 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
113 | * |
||
114 | * @return mixed |
||
115 | */ |
||
116 | function get_option( $option, $default = null, $network_level_or_blog_id = null ) { |
||
125 | |||
126 | /** |
||
127 | * @author Leo Fajardo (@leorw) |
||
128 | * @since 2.0.0 |
||
129 | * |
||
130 | * @param string $option |
||
131 | * @param mixed $value |
||
132 | * @param bool $flush |
||
133 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
134 | */ |
||
135 | function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) { |
||
143 | |||
144 | /** |
||
145 | * @author Vova Feldman (@svovaf) |
||
146 | * @since 2.0.0 |
||
147 | * |
||
148 | * @param string $option |
||
149 | * @param bool $flush |
||
150 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
151 | */ |
||
152 | function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) { |
||
160 | |||
161 | /** |
||
162 | * @author Leo Fajardo (@leorw) |
||
163 | * @since 2.0.0 |
||
164 | * |
||
165 | * @param bool $flush |
||
166 | * @param bool $network_level |
||
167 | */ |
||
168 | function load( $flush = false, $network_level = true ) { |
||
175 | |||
176 | /** |
||
177 | * @author Leo Fajardo (@leorw) |
||
178 | * @since 2.0.0 |
||
179 | * |
||
180 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, store both network storage and the current context blog storage. |
||
181 | */ |
||
182 | function store( $network_level_or_blog_id = null ) { |
||
198 | |||
199 | /** |
||
200 | * @author Vova Feldman (@svovaf) |
||
201 | * @since 2.0.0 |
||
202 | * |
||
203 | * @param int|null|bool $network_level_or_blog_id |
||
204 | * @param bool $flush |
||
205 | */ |
||
206 | function clear( $network_level_or_blog_id = null, $flush = false ) { |
||
222 | |||
223 | /** |
||
224 | * Migration script to the new storage data structure that is network compatible. |
||
225 | * |
||
226 | * IMPORTANT: |
||
227 | * This method should be executed only after it is determined if this is a network |
||
228 | * level compatible product activation. |
||
229 | * |
||
230 | * @author Vova Feldman (@svovaf) |
||
231 | * @since 2.0.0 |
||
232 | * |
||
233 | * @param int $blog_id |
||
234 | */ |
||
235 | function migrate_to_network( $blog_id = 0 ) { |
||
342 | |||
343 | |||
344 | #-------------------------------------------------------------------------------- |
||
345 | #region Helper Methods |
||
346 | #-------------------------------------------------------------------------------- |
||
347 | |||
348 | /** |
||
349 | * We don't want to load the map right away since it's not even needed in a non-MS environment. |
||
350 | * |
||
351 | * @author Vova Feldman (@svovaf) |
||
352 | * @since 2.0.0 |
||
353 | */ |
||
354 | private static function load_site_options_map() { |
||
362 | |||
363 | /** |
||
364 | * @author Vova Feldman (@svovaf) |
||
365 | * @since 2.0.0 |
||
366 | * |
||
367 | * @param string $option |
||
368 | * |
||
369 | * @return bool |
||
370 | */ |
||
371 | private function is_site_option( $option ) { |
||
382 | |||
383 | /** |
||
384 | * @author Vova Feldman (@svovaf) |
||
385 | * @since 2.0.0 |
||
386 | * |
||
387 | * @param int $blog_id |
||
388 | * |
||
389 | * @return FS_Option_Manager |
||
390 | */ |
||
391 | private function get_site_options( $blog_id = 0 ) { |
||
398 | |||
399 | /** |
||
400 | * Check if an option should be stored on the MS network storage. |
||
401 | * |
||
402 | * @author Vova Feldman (@svovaf) |
||
403 | * @since 2.0.0 |
||
404 | * |
||
405 | * @param string $option |
||
406 | * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_SITE_LEVEL_PARAMS). |
||
407 | * |
||
408 | * @return bool |
||
409 | */ |
||
410 | private function should_use_network_storage( $option, $network_level_or_blog_id = null ) { |
||
429 | |||
430 | #endregion |
||
431 | } |
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.