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 PradoBase 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 PradoBase, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
53 | class PradoBase |
||
54 | { |
||
55 | /** |
||
56 | * File extension for Prado class files. |
||
57 | */ |
||
58 | const CLASS_FILE_EXT = '.php'; |
||
59 | /** |
||
60 | * @var array list of path aliases |
||
61 | */ |
||
62 | private static $_aliases = [ |
||
63 | 'Prado' => PRADO_DIR, |
||
64 | 'Vendor' => PRADO_VENDORDIR |
||
65 | ]; |
||
66 | /** |
||
67 | * @var array list of namespaces currently in use |
||
68 | */ |
||
69 | private static $_usings = [ |
||
70 | 'Prado' => PRADO_DIR |
||
71 | ]; |
||
72 | /** |
||
73 | * @var array list of namespaces currently in use |
||
74 | */ |
||
75 | public static $classMap = []; |
||
76 | /** |
||
77 | * @var TApplication the application instance |
||
78 | */ |
||
79 | private static $_application = null; |
||
80 | /** |
||
81 | * @var TLogger logger instance |
||
82 | */ |
||
83 | private static $_logger = null; |
||
84 | /** |
||
85 | * @var array list of class exists checks |
||
86 | */ |
||
87 | protected static $classExists = []; |
||
88 | /** |
||
89 | * @return string the version of Prado framework |
||
90 | */ |
||
91 | 3 | public static function getVersion() |
|
95 | |||
96 | public static function init() |
||
101 | |||
102 | /** |
||
103 | * Loads the static classmap and registers the autoload function. |
||
104 | */ |
||
105 | public static function initAutoloader() |
||
111 | |||
112 | /** |
||
113 | * Initializes error handlers. |
||
114 | * This method set error and exception handlers to be functions |
||
115 | * defined in this class. |
||
116 | */ |
||
117 | public static function initErrorHandlers() |
||
136 | |||
137 | /** |
||
138 | * Class autoload loader. |
||
139 | * This method is provided to be invoked within an __autoload() magic method. |
||
140 | * @param string $className class name |
||
141 | */ |
||
142 | 7 | public static function autoload($className) |
|
146 | |||
147 | /** |
||
148 | * @param int $logoType the type of "powered logo". Valid values include 0 and 1. |
||
149 | * @return string a string that can be displayed on your Web page showing powered-by-PRADO information |
||
150 | */ |
||
151 | public static function poweredByPrado($logoType = 0) |
||
162 | |||
163 | /** |
||
164 | * PHP error handler. |
||
165 | * This method should be registered as PHP error handler using |
||
166 | * {@link set_error_handler}. The method throws an exception that |
||
167 | * contains the error information. |
||
168 | * @param int $errno the level of the error raised |
||
169 | * @param string $errstr the error message |
||
170 | * @param string $errfile the filename that the error was raised in |
||
171 | * @param int $errline the line number the error was raised at |
||
172 | */ |
||
173 | 14 | public static function phpErrorHandler($errno, $errstr, $errfile, $errline) |
|
179 | |||
180 | /** |
||
181 | * PHP shutdown function used to catch fatal errors. |
||
182 | * This method should be registered as PHP error handler using |
||
183 | * {@link register_shutdown_function}. The method throws an exception that |
||
184 | * contains the error information. |
||
185 | */ |
||
186 | public static function phpFatalErrorHandler() |
||
195 | |||
196 | /** |
||
197 | * Default exception handler. |
||
198 | * This method should be registered as default exception handler using |
||
199 | * {@link set_exception_handler}. The method tries to use the errorhandler |
||
200 | * module of the Prado application to handle the exception. |
||
201 | * If the application or the module does not exist, it simply echoes the |
||
202 | * exception. |
||
203 | * @param Exception $exception exception that is not caught |
||
204 | */ |
||
205 | public static function exceptionHandler($exception) |
||
214 | |||
215 | /** |
||
216 | * Stores the application instance in the class static member. |
||
217 | * This method helps implement a singleton pattern for TApplication. |
||
218 | * Repeated invocation of this method or the application constructor |
||
219 | * will cause the throw of an exception. |
||
220 | * This method should only be used by framework developers. |
||
221 | * @param TApplication $application the application instance |
||
222 | * @throws TInvalidOperationException if this method is invoked twice or more. |
||
223 | */ |
||
224 | 55 | public static function setApplication($application) |
|
231 | |||
232 | /** |
||
233 | * @return TApplication the application singleton, null if the singleton has not be created yet. |
||
234 | */ |
||
235 | 96 | public static function getApplication() |
|
239 | |||
240 | /** |
||
241 | * @return string the path of the framework |
||
242 | */ |
||
243 | 108 | public static function getFrameworkPath() |
|
247 | |||
248 | /** |
||
249 | * Convert old Prado namespaces to PHP namespaces |
||
250 | * @param string $type old class name in Prado3 namespace format |
||
251 | * @return string Equivalent class name in PHP namespace format |
||
252 | */ |
||
253 | 116 | protected static function prado3NamespaceToPhpNamespace($type) |
|
265 | |||
266 | /** |
||
267 | * Creates a component with the specified type. |
||
268 | * A component type can be either the component class name |
||
269 | * or a namespace referring to the path of the component class file. |
||
270 | * For example, 'TButton', '\Prado\Web\UI\WebControls\TButton' are both |
||
271 | * valid component type. |
||
272 | * This method can also pass parameters to component constructors. |
||
273 | * All parameters passed to this method except the first one (the component type) |
||
274 | * will be supplied as component constructor parameters. |
||
275 | * @param string $requestedType component type |
||
276 | * @param array $params |
||
277 | * @throws TInvalidDataValueException if the component type is unknown |
||
278 | * @return TComponent component instance of the specified type |
||
279 | */ |
||
280 | 103 | public static function createComponent($requestedType, ...$params) |
|
309 | |||
310 | /** |
||
311 | * Uses a namespace. |
||
312 | * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file. |
||
313 | * If the namespace corresponds to a directory, the directory will be appended |
||
314 | * to the include path. If the namespace corresponds to a file, it will be included (include_once). |
||
315 | * @param string $namespace namespace to be used |
||
316 | * @param bool $checkClassExistence whether to check the existence of the class after the class file is included |
||
317 | * @throws TInvalidDataValueException if the namespace is invalid |
||
318 | */ |
||
319 | 12 | public static function using($namespace, $checkClassExistence = true) |
|
377 | |||
378 | /** |
||
379 | * Translates a namespace into a file path. |
||
380 | * The first segment of the namespace is considered as a path alias |
||
381 | * which is replaced with the actual path. The rest segments are |
||
382 | * subdirectory names appended to the aliased path. |
||
383 | * If the namespace ends with an asterisk '*', it represents a directory; |
||
384 | * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty). |
||
385 | * Note, this method does not ensure the existence of the resulting file path. |
||
386 | * @param string $namespace namespace |
||
387 | * @param string $ext extension to be appended if the namespace refers to a file |
||
388 | * @return string file path corresponding to the namespace, null if namespace is invalid |
||
389 | */ |
||
390 | 10 | public static function getPathOfNamespace($namespace, $ext = '') |
|
413 | |||
414 | /** |
||
415 | * @param string $alias alias to the path |
||
416 | * @return string the path corresponding to the alias, null if alias not defined. |
||
417 | */ |
||
418 | 9 | public static function getPathOfAlias($alias) |
|
422 | |||
423 | protected static function getPathAliases() |
||
427 | |||
428 | /** |
||
429 | * @param string $alias alias to the path |
||
430 | * @param string $path the path corresponding to the alias |
||
431 | * @throws TInvalidOperationException $alias if the alias is already defined |
||
432 | * @throws TInvalidDataValueException $path if the path is not a valid file path |
||
433 | */ |
||
434 | 61 | public static function setPathOfAlias($alias, $path) |
|
448 | |||
449 | /** |
||
450 | * Fatal error handler. |
||
451 | * This method displays an error message together with the current call stack. |
||
452 | * The application will exit after calling this method. |
||
453 | * @param string $msg error message |
||
454 | */ |
||
455 | public static function fatalError($msg) |
||
515 | |||
516 | /** |
||
517 | * Returns a list of user preferred languages. |
||
518 | * The languages are returned as an array. Each array element |
||
519 | * represents a single language preference. The languages are ordered |
||
520 | * according to user preferences. The first language is the most preferred. |
||
521 | * @return array list of user preferred languages. |
||
522 | */ |
||
523 | 1 | public static function getUserLanguages() |
|
524 | { |
||
525 | 1 | static $languages = null; |
|
526 | 1 | if ($languages === null) { |
|
527 | 1 | if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { |
|
528 | $languages[0] = 'en'; |
||
529 | } else { |
||
530 | 1 | $languages = []; |
|
531 | 1 | foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) { |
|
532 | 1 | $array = explode(';q=', trim($language)); |
|
533 | 1 | $languages[trim($array[0])] = isset($array[1]) ? (float) $array[1] : 1.0; |
|
534 | } |
||
535 | 1 | arsort($languages); |
|
536 | 1 | $languages = array_keys($languages); |
|
537 | 1 | if (empty($languages)) { |
|
538 | $languages[0] = 'en'; |
||
539 | } |
||
540 | } |
||
541 | } |
||
542 | 1 | return $languages; |
|
543 | } |
||
544 | |||
545 | /** |
||
546 | * Returns the most preferred language by the client user. |
||
547 | * @return string the most preferred language by the client user, defaults to English. |
||
548 | */ |
||
549 | 113 | public static function getPreferredLanguage() |
|
563 | |||
564 | /** |
||
565 | * Writes a log message. |
||
566 | * This method wraps {@link log()} by checking the application mode. |
||
567 | * When the application is in Debug mode, debug backtrace information is appended |
||
568 | * to the message and the message is logged at DEBUG level. |
||
569 | * When the application is in Performance mode, this method does nothing. |
||
570 | * Otherwise, the message is logged at INFO level. |
||
571 | * @param string $msg message to be logged |
||
572 | * @param string $category category of the message |
||
573 | * @param (string|TControl) $ctl control of the message |
||
574 | * @see log, getLogger |
||
575 | */ |
||
576 | 32 | public static function trace($msg, $category = 'Uncategorized', $ctl = null) |
|
592 | |||
593 | /** |
||
594 | * Logs a message. |
||
595 | * Messages logged by this method may be retrieved via {@link TLogger::getLogs} |
||
596 | * and may be recorded in different media, such as file, email, database, using |
||
597 | * {@link TLogRouter}. |
||
598 | * @param string $msg message to be logged |
||
599 | * @param int $level level of the message. Valid values include |
||
600 | * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING, |
||
601 | * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL. |
||
602 | * @param string $category category of the message |
||
603 | * @param (string|TControl) $ctl control of the message |
||
604 | */ |
||
605 | 32 | public static function log($msg, $level = TLogger::INFO, $category = 'Uncategorized', $ctl = null) |
|
606 | { |
||
607 | 32 | if (self::$_logger === null) { |
|
608 | 1 | self::$_logger = new TLogger; |
|
609 | } |
||
610 | 32 | self::$_logger->log($msg, $level, $category, $ctl); |
|
611 | 32 | } |
|
612 | |||
613 | /** |
||
614 | * @return TLogger message logger |
||
615 | */ |
||
616 | public static function getLogger() |
||
623 | |||
624 | /** |
||
625 | * Converts a variable into a string representation. |
||
626 | * This method achieves the similar functionality as var_dump and print_r |
||
627 | * but is more robust when handling complex objects such as PRADO controls. |
||
628 | * @param mixed $var variable to be dumped |
||
629 | * @param int $depth maximum depth that the dumper should go into the variable. Defaults to 10. |
||
630 | * @param bool $highlight whether to syntax highlight the output. Defaults to false. |
||
631 | * @return string the string representation of the variable |
||
632 | */ |
||
633 | public static function varDump($var, $depth = 10, $highlight = false) |
||
637 | |||
638 | /** |
||
639 | * Localize a text to the locale/culture specified in the globalization handler. |
||
640 | * @param string $text text to be localized. |
||
641 | * @param array $parameters a set of parameters to substitute. |
||
642 | * @param string $catalogue a different catalogue to find the localize text. |
||
643 | * @param string $charset the input AND output charset. |
||
644 | * @return string localized text. |
||
645 | * @see TTranslate::formatter() |
||
646 | * @see TTranslate::init() |
||
647 | */ |
||
648 | public static function localize($text, $parameters = [], $catalogue = null, $charset = null) |
||
684 | } |
||
685 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.