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 Jaxon 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 Jaxon, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
35 | class Jaxon |
||
36 | { |
||
37 | use \Jaxon\Utils\Traits\Config; |
||
38 | use \Jaxon\Utils\Traits\Manager; |
||
39 | use \Jaxon\Utils\Traits\Translator; |
||
40 | use \Jaxon\Utils\Traits\Paginator; |
||
41 | use \Jaxon\Utils\Traits\Template; |
||
42 | |||
43 | /** |
||
44 | * Package version number |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | private $sVersion = 'Jaxon 2.0.4'; |
||
49 | |||
50 | /* |
||
51 | * Processing events |
||
52 | */ |
||
53 | const PROCESSING_EVENT = 'ProcessingEvent'; |
||
54 | const PROCESSING_EVENT_BEFORE = 'BeforeProcessing'; |
||
55 | const PROCESSING_EVENT_AFTER = 'AfterProcessing'; |
||
56 | const PROCESSING_EVENT_INVALID = 'InvalidRequest'; |
||
57 | const PROCESSING_EVENT_ERROR = 'ProcessingError'; |
||
58 | |||
59 | /* |
||
60 | * Request methods |
||
61 | */ |
||
62 | const METHOD_UNKNOWN = 0; |
||
63 | const METHOD_GET = 1; |
||
64 | const METHOD_POST = 2; |
||
65 | |||
66 | /* |
||
67 | * Request plugins |
||
68 | */ |
||
69 | // For objects who's methods will be callable from the browser. |
||
70 | const CALLABLE_OBJECT = 'CallableObject'; |
||
71 | // For functions available at global scope, or from an instance of an object. |
||
72 | const USER_FUNCTION = 'UserFunction'; |
||
73 | // For browser events. |
||
74 | const BROWSER_EVENT = 'BrowserEvent'; |
||
75 | // For event handlers. |
||
76 | const EVENT_HANDLER = 'EventHandler'; |
||
77 | // For uploaded files. |
||
78 | const FILE_UPLOAD = 'FileUpload'; |
||
79 | |||
80 | /* |
||
81 | * Request parameters |
||
82 | */ |
||
83 | // Specifies that the parameter will consist of an array of form values. |
||
84 | const FORM_VALUES = 'FormValues'; |
||
85 | // Specifies that the parameter will contain the value of an input control. |
||
86 | const INPUT_VALUE = 'InputValue'; |
||
87 | // Specifies that the parameter will consist of a boolean value of a checkbox. |
||
88 | const CHECKED_VALUE = 'CheckedValue'; |
||
89 | // Specifies that the parameter value will be the innerHTML value of the element. |
||
90 | const ELEMENT_INNERHTML = 'ElementInnerHTML'; |
||
91 | // Specifies that the parameter will be a quoted value (string). |
||
92 | const QUOTED_VALUE = 'QuotedValue'; |
||
93 | // Specifies that the parameter will be a boolean value (true or false). |
||
94 | const BOOL_VALUE = 'BoolValue'; |
||
95 | // Specifies that the parameter will be a numeric, non-quoted value. |
||
96 | const NUMERIC_VALUE = 'NumericValue'; |
||
97 | // Specifies that the parameter will be a non-quoted value |
||
98 | // (evaluated by the browsers javascript engine at run time). |
||
99 | const JS_VALUE = 'UnquotedValue'; |
||
100 | // Specifies that the parameter will be an integer used to generate pagination links. |
||
101 | const PAGE_NUMBER = 'PageNumber'; |
||
102 | |||
103 | /** |
||
104 | * Processing event handlers that have been assigned during this run of the script |
||
105 | * |
||
106 | * @var array |
||
107 | */ |
||
108 | private $aProcessingEvents; |
||
109 | |||
110 | public function __construct() |
||
115 | |||
116 | /** |
||
117 | * Set the default options of all components of the library |
||
118 | * |
||
119 | * @return void |
||
120 | */ |
||
121 | private function setDefaultOptions() |
||
152 | |||
153 | /** |
||
154 | * Set Jaxon to use the Composer autoloader |
||
155 | * |
||
156 | * @return void |
||
157 | */ |
||
158 | public function useComposerAutoloader() |
||
162 | |||
163 | /** |
||
164 | * Disable Jaxon classes autoloading |
||
165 | * |
||
166 | * @return void |
||
167 | */ |
||
168 | public function disableAutoload() |
||
172 | |||
173 | /** |
||
174 | * The current Jaxon version |
||
175 | * |
||
176 | * @return string |
||
177 | */ |
||
178 | public function getVersion() |
||
182 | |||
183 | /** |
||
184 | * Register request handlers, including functions, callable objects and events. |
||
185 | * |
||
186 | * New plugins can be added that support additional registration methods and request processors. |
||
187 | * |
||
188 | * @param string $sType The type of request handler being registered |
||
189 | * Options include: |
||
190 | * - Jaxon::USER_FUNCTION: a function declared at global scope |
||
191 | * - Jaxon::CALLABLE_OBJECT: an object who's methods are to be registered |
||
192 | * - Jaxon::BROWSER_EVENT: an event which will cause zero or more event handlers to be called |
||
193 | * - Jaxon::EVENT_HANDLER: register an event handler function. |
||
194 | * @param mixed $sFunction | $objObject | $sEvent |
||
195 | * When registering a function, this is the name of the function |
||
196 | * When registering a callable object, this is the object being registered |
||
197 | * When registering an event or event handler, this is the name of the event |
||
198 | * @param mixed $sIncludeFile | $aCallOptions | $sEventHandler |
||
199 | * When registering a function, this is the (optional) include file |
||
200 | * When registering a callable object, this is an (optional) array |
||
201 | * of call options for the functions being registered |
||
202 | * When registering an event handler, this is the name of the function |
||
203 | * |
||
204 | * @return mixed |
||
205 | */ |
||
206 | public function register($sType, $xArgs) |
||
230 | |||
231 | /** |
||
232 | * Add a path to the class directories |
||
233 | * |
||
234 | * @param string $sDirectory The path to the directory |
||
235 | * @param string|null $sNamespace The associated namespace |
||
236 | * @param string $sSeparator The character to use as separator in javascript class names |
||
237 | * @param array $aProtected The functions that are not to be exported |
||
238 | * |
||
239 | * @return boolean |
||
240 | */ |
||
241 | public function addClassDir($sDirectory, $sNamespace = null, $sSeparator = '.', array $aProtected = array()) |
||
245 | |||
246 | /** |
||
247 | * Register callable objects from all class directories |
||
248 | * |
||
249 | * @param array $aOptions The options to register the classes with |
||
250 | * |
||
251 | * @return void |
||
252 | */ |
||
253 | public function registerClasses(array $aOptions = array()) |
||
257 | |||
258 | /** |
||
259 | * Register a callable object from one of the class directories |
||
260 | * |
||
261 | * The class name can be dot, slash or anti-slash separated. |
||
262 | * If the $bGetObject parameter is set to true, the registered instance of the class is returned. |
||
263 | * |
||
264 | * @param string $sClassName The name of the class to register |
||
265 | * @param array $aOptions The options to register the class with |
||
266 | * @param boolean $bGetObject Return the registered instance of the class |
||
267 | * |
||
268 | * @return void |
||
269 | */ |
||
270 | public function registerClass($sClassName, array $aOptions = array(), $bGetObject = false) |
||
275 | |||
276 | /** |
||
277 | * Determine if a call is a jaxon request or a page load request |
||
278 | * |
||
279 | * @return boolean |
||
280 | */ |
||
281 | public function canProcessRequest() |
||
285 | |||
286 | /** |
||
287 | * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser |
||
288 | * |
||
289 | * This is the main server side engine for Jaxon. |
||
290 | * It handles all the incoming requests, including the firing of events and handling of the response. |
||
291 | * If your RequestURI is the same as your web page, then this function should be called before ANY |
||
292 | * headers or HTML is output from your script. |
||
293 | * |
||
294 | * This function may exit after the request is processed, if the 'core.process.exit' option is set to true. |
||
295 | * |
||
296 | * @return void |
||
297 | * |
||
298 | * @see <Jaxon\Jaxon->canProcessRequest> |
||
299 | */ |
||
300 | public function processRequest() |
||
397 | |||
398 | /** |
||
399 | * Send the response output back to the browser |
||
400 | * |
||
401 | * @return void |
||
402 | */ |
||
403 | public function sendResponse() |
||
407 | |||
408 | /** |
||
409 | * Send the HTTP headers back to the browser |
||
410 | * |
||
411 | * @return void |
||
412 | */ |
||
413 | public function sendHeaders() |
||
417 | |||
418 | /** |
||
419 | * Get the response output |
||
420 | * |
||
421 | * @return string |
||
422 | */ |
||
423 | public function getOutput() |
||
427 | |||
428 | /** |
||
429 | * Returns the Jaxon Javascript header and wrapper code to be printed into the page |
||
430 | * |
||
431 | * The javascript code returned by this function is dependent on the plugins |
||
432 | * that are included and the functions and classes that are registered. |
||
433 | * |
||
434 | * @param boolean $bIncludeJs Also get the JS files |
||
435 | * @param boolean $bIncludeCss Also get the CSS files |
||
436 | * |
||
437 | * @return string |
||
438 | */ |
||
439 | public function getScript($bIncludeJs = false, $bIncludeCss = false) |
||
457 | |||
458 | /** |
||
459 | * Print the jaxon Javascript header and wrapper code into your page |
||
460 | * |
||
461 | * The javascript code returned by this function is dependent on the plugins |
||
462 | * that are included and the functions and classes that are registered. |
||
463 | * |
||
464 | * @param boolean $bIncludeJs Also print the JS files |
||
465 | * @param boolean $bIncludeCss Also print the CSS files |
||
466 | * |
||
467 | * @return void |
||
468 | */ |
||
469 | public function printScript($bIncludeJs = false, $bIncludeCss = false) |
||
473 | |||
474 | /** |
||
475 | * Return the javascript header code and file includes |
||
476 | * |
||
477 | * @return string |
||
478 | */ |
||
479 | public function getJs() |
||
483 | |||
484 | /** |
||
485 | * Return the CSS header code and file includes |
||
486 | * |
||
487 | * @return string |
||
488 | */ |
||
489 | public function getCss() |
||
493 | |||
494 | /** |
||
495 | * Read and set Jaxon options from a PHP config file |
||
496 | * |
||
497 | * @param string $sConfigFile The full path to the config file |
||
498 | * @param string $sLibKey The key of the library options in the file |
||
499 | * @param string|null $sAppKey The key of the application options in the file |
||
500 | * |
||
501 | * @return array |
||
502 | */ |
||
503 | public function readPhpConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null) |
||
507 | |||
508 | /** |
||
509 | * Read and set Jaxon options from a YAML config file |
||
510 | * |
||
511 | * @param string $sConfigFile The full path to the config file |
||
512 | * @param string $sLibKey The key of the library options in the file |
||
513 | * @param string|null $sAppKey The key of the application options in the file |
||
514 | * |
||
515 | * @return array |
||
516 | */ |
||
517 | public function readYamlConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null) |
||
521 | |||
522 | /** |
||
523 | * Read and set Jaxon options from a JSON config file |
||
524 | * |
||
525 | * @param string $sConfigFile The full path to the config file |
||
526 | * @param string $sLibKey The key of the library options in the file |
||
527 | * @param string|null $sAppKey The key of the application options in the file |
||
528 | * |
||
529 | * @return array |
||
530 | */ |
||
531 | public function readJsonConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null) |
||
535 | |||
536 | /** |
||
537 | * Read and set Jaxon options from a config file |
||
538 | * |
||
539 | * @param string $sConfigFile The full path to the config file |
||
540 | * @param string $sLibKey The key of the library options in the file |
||
541 | * @param string|null $sAppKey The key of the application options in the file |
||
542 | * |
||
543 | * @return array |
||
544 | */ |
||
545 | public function readConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null) |
||
562 | |||
563 | /** |
||
564 | * Register a plugin |
||
565 | * |
||
566 | * Below is a table for priorities and their description: |
||
567 | * - 0 thru 999: Plugins that are part of or extensions to the jaxon core |
||
568 | * - 1000 thru 8999: User created plugins, typically, these plugins don't care about order |
||
569 | * - 9000 thru 9999: Plugins that generally need to be last or near the end of the plugin list |
||
570 | * |
||
571 | * @param Plugin $xPlugin An instance of a plugin |
||
572 | * @param integer $nPriority The plugin priority, used to order the plugins |
||
573 | * |
||
574 | * @return void |
||
575 | */ |
||
576 | public function registerPlugin(\Jaxon\Plugin\Plugin $xPlugin, $nPriority = 1000) |
||
580 | |||
581 | /** |
||
582 | * Register the Jaxon request plugins |
||
583 | * |
||
584 | * @return void |
||
585 | */ |
||
586 | public function registerRequestPlugins() |
||
593 | |||
594 | /** |
||
595 | * Register the Jaxon response plugins |
||
596 | * |
||
597 | * @return void |
||
598 | */ |
||
599 | public function registerResponsePlugins() |
||
604 | |||
605 | /** |
||
606 | * Set a new directory for pagination templates |
||
607 | * |
||
608 | * @param string $sDirectory The directory path |
||
609 | * |
||
610 | * @return void |
||
611 | */ |
||
612 | public function setPaginationDir($sDirectory) |
||
616 | |||
617 | /** |
||
618 | * Check if uploaded files are available |
||
619 | * |
||
620 | * @return boolean |
||
621 | */ |
||
622 | public function hasUploadedFiles() |
||
630 | |||
631 | /** |
||
632 | * Check uploaded files validity and move them to the user dir |
||
633 | * |
||
634 | * @return boolean |
||
635 | */ |
||
636 | public function saveUploadedFiles() |
||
666 | |||
667 | /** |
||
668 | * Get the uploaded files |
||
669 | * |
||
670 | * @return array |
||
671 | */ |
||
672 | public function getUploadedFiles() |
||
680 | |||
681 | /** |
||
682 | * Filter uploaded file name |
||
683 | * |
||
684 | * @param Closure $fFileFilter The closure which filters filenames |
||
685 | * |
||
686 | * @return void |
||
687 | */ |
||
688 | public function setUploadFileFilter($fFileFilter) |
||
696 | |||
697 | /** |
||
698 | * Get the Sentry instance |
||
699 | * |
||
700 | * @return \Jaxon\Sentry\Sentry |
||
701 | */ |
||
702 | public function sentry() |
||
706 | |||
707 | /** |
||
708 | * Get the Armada instance |
||
709 | * |
||
710 | * @return \Jaxon\Sentry\Traits\Armada |
||
711 | */ |
||
712 | public function armada() |
||
716 | } |
||
717 |
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exit
expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.