Complex classes like code_review 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 code_review, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
7 | class code_review { |
||
|
|||
8 | |||
9 | /** |
||
10 | * Config array to allow mocking of configuration. |
||
11 | * |
||
12 | * @var array |
||
13 | */ |
||
14 | protected static $config = array(); |
||
15 | |||
16 | /** |
||
17 | * @codeCoverageIgnore |
||
18 | */ |
||
19 | public static function boot() { |
||
36 | |||
37 | /** |
||
38 | * @return array |
||
39 | */ |
||
40 | 1 | public static function getConfig() { |
|
43 | |||
44 | /** |
||
45 | * @param array $options |
||
46 | * |
||
47 | * @todo Move into CodeReviewConfig instead |
||
48 | */ |
||
49 | 5 | public static function initConfig(array $options) { |
|
65 | |||
66 | /** |
||
67 | * @codeCoverageIgnore |
||
68 | */ |
||
69 | public static function init() { |
||
81 | |||
82 | /** |
||
83 | * @codeCoverageIgnore |
||
84 | */ |
||
85 | public static function pagesetup() { |
||
96 | |||
97 | /** |
||
98 | * @codeCoverageIgnore |
||
99 | */ |
||
100 | public static function menu_register() { |
||
126 | |||
127 | /** |
||
128 | * @param string $subPath |
||
129 | * @return RegexIterator |
||
130 | */ |
||
131 | 4 | public static function getPhpIterator($subPath = '/') { |
|
137 | |||
138 | 1 | public static function getVersionsList() { |
|
139 | 1 | $i = self::getPhpIterator('lib/'); |
|
140 | 1 | $i = new RegexIterator($i, "/deprecated-.*/"); |
|
141 | |||
142 | 1 | $vv = array(); |
|
143 | |||
144 | 1 | foreach ($i as $file) { |
|
145 | 1 | if ($file instanceof SplFileInfo) { |
|
146 | 1 | if (preg_match('#^deprecated-([0-9\.]*)$#', $file->getBasename('.php'), $matches)) { |
|
147 | 1 | $version = $matches[1]; |
|
148 | 1 | } else { |
|
149 | $version = null; |
||
150 | } |
||
151 | 1 | if ($version !== null) { |
|
152 | 1 | $vv[] = $version; |
|
153 | 1 | } |
|
154 | 1 | } |
|
155 | 1 | } |
|
156 | 1 | usort($vv, 'version_compare'); |
|
157 | 1 | return $vv; |
|
158 | } |
||
159 | |||
160 | /** |
||
161 | * @val string |
||
162 | */ |
||
163 | const DEPRECATED_TAG_PREFIX = 'deprecated'; |
||
164 | |||
165 | |||
166 | /** |
||
167 | * @val string |
||
168 | */ |
||
169 | const PRIVATE_TAG_PREFIX = 'private'; |
||
170 | |||
171 | /** |
||
172 | * Filtering predicate |
||
173 | * |
||
174 | * @param $e |
||
175 | * @return bool |
||
176 | */ |
||
177 | 2 | public static function filterTagsByDeprecatedPrefix($e) { |
|
180 | |||
181 | /** |
||
182 | * Filtering predicate |
||
183 | * |
||
184 | * @param $e |
||
185 | * @return bool |
||
186 | */ |
||
187 | public static function filterTagsByPrivatePrefix($e) { |
||
190 | |||
191 | 2 | private static function getDeprecatedInfoFromDocBlock($deprecatedInfo, $maxVersion) { |
|
234 | |||
235 | private static function getPrivateInfoFromDocBlock($privateInfo) { |
||
245 | |||
246 | /** |
||
247 | * @param string $maxVersion |
||
248 | * @return array |
||
249 | */ |
||
250 | 2 | public static function getDeprecatedFunctionsList($maxVersion = '') { |
|
280 | |||
281 | /** |
||
282 | * @param string $maxVersion |
||
283 | * @return array |
||
284 | */ |
||
285 | 1 | public static function getPrivateFunctionsList() { |
|
304 | |||
305 | /** |
||
306 | * Redurns deprecated functions from particular file. |
||
307 | * |
||
308 | * @param PhpFileParser $tokens |
||
309 | * @param SplFileInfo $file |
||
310 | * @param $version |
||
311 | * @param $maxVersion max version to return |
||
312 | * @return array |
||
313 | */ |
||
314 | 2 | private static function getDeprecatedFunctionsFromTokens(PhpFileParser $tokens, SplFileInfo $file, $version, $maxVersion) { |
|
315 | 2 | $namespace = ''; |
|
316 | 2 | $className = null; |
|
317 | 2 | $functs = array(); |
|
318 | 2 | foreach ($tokens as $key => $token) { |
|
319 | 2 | if ($tokens->isEqualToToken(T_INTERFACE, $key)) { |
|
320 | //we don't process interfaces for deprecated functions |
||
321 | break; |
||
322 | } |
||
323 | 2 | if ($tokens->isEqualToToken(T_NAMESPACE, $key)) { |
|
324 | 2 | $pos = $key+2; |
|
325 | 2 | $namespace = ''; |
|
326 | 2 | while (isset($tokens[$pos]) && $tokens[$pos] !== ';') { |
|
327 | 2 | $namespace .= $tokens[$pos][1]; |
|
328 | 2 | $pos++; |
|
329 | 2 | } |
|
330 | 2 | $namespace = '\\' . $namespace . '\\'; |
|
331 | 2 | } |
|
332 | 2 | if ($tokens->isEqualToToken(T_CLASS, $key)) { |
|
333 | //mark class name for all following functions |
||
334 | 2 | $className = $namespace . $tokens[$key+2][1]; |
|
335 | 2 | } |
|
336 | |||
337 | //TODO we need to filter out closures |
||
338 | |||
339 | 2 | if ($tokens->isEqualToToken(T_FUNCTION, $key)) { |
|
340 | 2 | if ($className !== null) { |
|
341 | 2 | $functionName = $className . '::' . $tokens[$key+2][1]; |
|
342 | try { |
||
343 | 2 | $reflection = new ReflectionMethod($className, $tokens[$key+2][1]); |
|
344 | 2 | } catch (ReflectionException $e) { |
|
345 | // var_dump($className, $functionName, $e->getMessage()); |
||
1 ignored issue
–
show
|
|||
346 | continue; |
||
347 | } |
||
348 | |||
349 | 2 | } else { |
|
350 | 1 | $functionName = $tokens[$key+2][1]; |
|
351 | try { |
||
352 | 1 | $reflection = new ReflectionFunction($functionName); |
|
353 | 1 | } catch (ReflectionException $e) { |
|
354 | // var_dump($functionName, $e->getMessage()); |
||
1 ignored issue
–
show
|
|||
355 | continue; |
||
356 | } |
||
357 | } |
||
358 | |||
359 | //check if non empty version and try go guess |
||
360 | $data = array( |
||
361 | 2 | 'name' => $functionName, |
|
362 | 2 | 'version' => $version, |
|
363 | 2 | 'file' => $file->getPathname(), |
|
364 | 2 | 'line' => $token[2], |
|
365 | 2 | ); |
|
366 | |||
367 | 2 | $docBlock = $reflection->getDocComment(); |
|
368 | 2 | if ($docBlock) { |
|
369 | 2 | $info = self::getDeprecatedInfoFromDocBlock($docBlock, $maxVersion); |
|
370 | 2 | if (!$info) { |
|
371 | 2 | if ($version) { |
|
372 | // no details, but we have version, so everything is deprecated here |
||
373 | $info = array( |
||
374 | 1 | 'deprecated' => true, |
|
375 | 1 | 'version' => $version, |
|
376 | 1 | 'fixinfoshort' => false, |
|
377 | 1 | ); |
|
378 | 1 | } else { |
|
379 | //skipping - not deprecated |
||
380 | 2 | continue; |
|
381 | } |
||
382 | 1 | } |
|
383 | 2 | $data = array_merge($data, $info); |
|
384 | 2 | } |
|
385 | |||
386 | 2 | $functs[strtolower($functionName)] = new CodeReview_Issues_Deprecated($data); |
|
387 | 2 | } |
|
388 | 2 | } |
|
389 | 2 | return $functs; |
|
390 | } |
||
391 | |||
392 | /** |
||
393 | * Redurns deprecated functions from particular file. |
||
394 | * |
||
395 | * @param PhpFileParser $tokens |
||
396 | * @param SplFileInfo $file |
||
397 | * @param $version |
||
398 | * @return array |
||
399 | */ |
||
400 | 1 | private static function getPrivateFunctionsFromTokens(PhpFileParser $tokens, SplFileInfo $file) { |
|
464 | |||
465 | /** |
||
466 | * Returns a list of plugin directory names from a base directory. |
||
467 | * Copied from 1.9 core due to elgg_get_plugin_ids_in_dir removal in 1.9 |
||
468 | * |
||
469 | * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path. |
||
470 | * Must have a trailing slash. |
||
471 | * |
||
472 | * @return array Array of directory names (not full paths) |
||
473 | */ |
||
474 | 1 | public static function getPluginDirsInDir($dir = null) { |
|
495 | } |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.