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 Addons 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 Addons, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class Addons { |
||
22 | /// Constants /// |
||
23 | const K_BOOTSTRAP = 'bootstrap'; // bootstrap path key |
||
24 | const K_CLASSES = 'classes'; |
||
25 | const K_DIR = 'dir'; |
||
26 | const K_INFO = 'info'; // addon info key |
||
27 | |||
28 | /// Properties /// |
||
29 | |||
30 | /** |
||
31 | * @var array An array that maps addon keys to full addon information. |
||
32 | */ |
||
33 | protected static $all; |
||
34 | |||
35 | /** |
||
36 | * @var string The base directory where all of the addons are found. |
||
37 | */ |
||
38 | protected static $baseDir; |
||
39 | |||
40 | /** |
||
41 | * @var array An array that maps class names to their fully namespaced class names. |
||
42 | */ |
||
43 | // protected static $basenameMap; |
||
44 | |||
45 | /** |
||
46 | * @var array|null An array that maps class names to file paths. |
||
47 | */ |
||
48 | protected static $classMap; |
||
49 | |||
50 | /** |
||
51 | * @var array An array that maps addon keys to full addon information for enabled addons. |
||
52 | */ |
||
53 | protected static $enabled; |
||
54 | |||
55 | /** |
||
56 | * @var array An array of enabled addon keys. |
||
57 | */ |
||
58 | protected static $enabledKeys; |
||
59 | |||
60 | /** |
||
61 | * @var bool Signals that the addon framework is in a shared environment and shouldn't use the enabled cache. |
||
62 | */ |
||
63 | public static $sharedEnvironment; |
||
64 | |||
65 | /// Methods /// |
||
66 | |||
67 | /** |
||
68 | * Get all of the available addons or a single addon from the available list. |
||
69 | * |
||
70 | * @param string $addon_key If you supply an addon key then only that addon will be returned. |
||
71 | * @param string $key Supply one of the Addons::K_* constants to get a specific key from the addon. |
||
72 | * @return array Returns the addon with the given key or all available addons if no key is passed. |
||
73 | */ |
||
74 | public static function all($addon_key = null, $key = null) { |
||
93 | |||
94 | /** |
||
95 | * An autoloader that will autoload a class based on which addons are enabled. |
||
96 | * |
||
97 | * @param string $classname The name of the class to load. |
||
98 | */ |
||
99 | 6 | public static function autoload($classname) { |
|
105 | |||
106 | /** |
||
107 | * Gets/sets the base directory for addons. |
||
108 | * |
||
109 | * @param string $value Pass a value to set the new base directory. |
||
110 | * @return string Returns the base directory for addons. |
||
111 | */ |
||
112 | 34 | public static function baseDir($value = null) { |
|
119 | |||
120 | |||
121 | /** |
||
122 | * Start up the addon framework. |
||
123 | * |
||
124 | * @param array $enabled_addons An array of enabled addons. |
||
125 | */ |
||
126 | 34 | public static function bootstrap($enabled_addons = null) { |
|
165 | |||
166 | /** |
||
167 | * Get the cached file or hydrate the cache with a callback. |
||
168 | * |
||
169 | * @param string $key The cache key to get. |
||
170 | * @param callable $cache_cb The function to run when hydrating the cache. |
||
171 | * @return array Returns the cached array. |
||
172 | */ |
||
173 | 1 | protected static function cacheGet($key, callable $cache_cb) { |
|
187 | |||
188 | /** |
||
189 | * A an array that maps class names to physical paths. |
||
190 | * |
||
191 | * @param string $classname An optional class name to get the path of. |
||
192 | * @return array Returns an array in the form `[fullClassname, classPath]`. |
||
193 | * If no {@link $classname} is passed then the entire class map is returned. |
||
194 | * @throws \Exception Throws an exception if the class map is corrupt. |
||
195 | */ |
||
196 | 36 | public static function classMap($classname = null) { |
|
231 | |||
232 | /** |
||
233 | * Get all of the enabled addons or a single addon from the enabled list. |
||
234 | * |
||
235 | * @param string $addon_key If you supply an addon key then only that addon will be returned. |
||
236 | * @param string $key Supply one of the Addons::K_* constants to get a specific key from the addon. |
||
237 | * @return array Returns the addon with the given key or all enabled addons if no key is passed. |
||
238 | * @throws \Exception Throws an exception if {@link Addons::bootstrap()} hasn't been called yet. |
||
239 | */ |
||
240 | 34 | public static function enabled($addon_key = null, $key = null) { |
|
278 | |||
279 | /** |
||
280 | * Return the info array for an addon. |
||
281 | * |
||
282 | * @param string $addon_key The addon key. |
||
283 | * @return array|null Returns the addon's info array or null if the addon wasn't found. |
||
284 | */ |
||
285 | public static function info($addon_key) { |
||
295 | |||
296 | /** |
||
297 | * Scan an addon directory for information. |
||
298 | * |
||
299 | * @param string $dir The addon directory to scan. |
||
300 | * @param array &$addons The addons array. |
||
301 | * @param array $enabled An array of enabled addons or null to scan all addons. |
||
302 | * @return array Returns an array in the form [addonKey, addonInfo]. |
||
303 | */ |
||
304 | 1 | protected static function scanAddonRecursive($dir, &$addons, $enabled = null) { |
|
330 | |||
331 | /** |
||
332 | * Scan an individual addon directory and return the information about that addon. |
||
333 | * |
||
334 | * @param string $dir The path to the addon. |
||
335 | * @return array An array in the form of `[$addon_key, $addon_row]` or `[$addon_key, null]` if the directory doesn't |
||
336 | * represent an addon. |
||
337 | */ |
||
338 | 1 | protected static function scanAddon($dir) { |
|
393 | |||
394 | /** |
||
395 | * Scan a directory for addons. |
||
396 | * |
||
397 | * @param string $dir The directory to scan. |
||
398 | * @param array $enabled An array of enabled addons in the form `[addonKey => enabled, ...]`. |
||
399 | * @param array &$addons The addons will fill this array. |
||
400 | * @return array Returns all of the addons. |
||
401 | */ |
||
402 | 1 | protected static function scanAddons($dir = null, $enabled = null, &$addons = null) { |
|
419 | |||
420 | /** |
||
421 | * Looks what classes and namespaces are defined in a file and returns the first found. |
||
422 | * |
||
423 | * @param string $file Path to file. |
||
424 | * @return array Returns an empty array if no classes are found or an array with namespaces and |
||
425 | * classes found in the file. |
||
426 | * @see http://stackoverflow.com/a/11114724/1984219 |
||
427 | */ |
||
428 | 1 | protected static function scanFile($file) { |
|
481 | |||
482 | /** |
||
483 | * Start an addon. |
||
484 | * |
||
485 | * This function does the following: |
||
486 | * |
||
487 | * 1. Make the addon available in the autoloader. |
||
488 | * 2. Run the addon's bootstrap.php if it exists. |
||
489 | * |
||
490 | * @param string $addon_key The key of the addon to enable. |
||
491 | * @return bool Returns true if the addon was enabled. False otherwise. |
||
492 | */ |
||
493 | 34 | public static function startAddon($addon_key) { |
|
505 | } |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: