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 FirePHP 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 FirePHP, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
58 | class FirePHP { |
||
59 | |||
60 | /** |
||
61 | * FirePHP version |
||
62 | * |
||
63 | * @var string |
||
64 | */ |
||
65 | const VERSION = '0.3'; |
||
66 | |||
67 | /** |
||
68 | * Firebug LOG level |
||
69 | * |
||
70 | * Logs a message to firebug console. |
||
71 | * |
||
72 | * @var string |
||
73 | */ |
||
74 | const LOG = 'LOG'; |
||
75 | |||
76 | /** |
||
77 | * Firebug INFO level |
||
78 | * |
||
79 | * Logs a message to firebug console and displays an info icon before the message. |
||
80 | * |
||
81 | * @var string |
||
82 | */ |
||
83 | const INFO = 'INFO'; |
||
84 | |||
85 | /** |
||
86 | * Firebug WARN level |
||
87 | * |
||
88 | * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. |
||
89 | * |
||
90 | * @var string |
||
91 | */ |
||
92 | const WARN = 'WARN'; |
||
93 | |||
94 | /** |
||
95 | * Firebug ERROR level |
||
96 | * |
||
97 | * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. |
||
98 | * |
||
99 | * @var string |
||
100 | */ |
||
101 | const ERROR = 'ERROR'; |
||
102 | |||
103 | /** |
||
104 | * Dumps a variable to firebug's server panel |
||
105 | * |
||
106 | * @var string |
||
107 | */ |
||
108 | const DUMP = 'DUMP'; |
||
109 | |||
110 | /** |
||
111 | * Displays a stack trace in firebug console |
||
112 | * |
||
113 | * @var string |
||
114 | */ |
||
115 | const TRACE = 'TRACE'; |
||
116 | |||
117 | /** |
||
118 | * Displays an exception in firebug console |
||
119 | * |
||
120 | * Increments the firebug error count. |
||
121 | * |
||
122 | * @var string |
||
123 | */ |
||
124 | const EXCEPTION = 'EXCEPTION'; |
||
125 | |||
126 | /** |
||
127 | * Displays an table in firebug console |
||
128 | * |
||
129 | * @var string |
||
130 | */ |
||
131 | const TABLE = 'TABLE'; |
||
132 | |||
133 | /** |
||
134 | * Starts a group in firebug console |
||
135 | * |
||
136 | * @var string |
||
137 | */ |
||
138 | const GROUP_START = 'GROUP_START'; |
||
139 | |||
140 | /** |
||
141 | * Ends a group in firebug console |
||
142 | * |
||
143 | * @var string |
||
144 | */ |
||
145 | const GROUP_END = 'GROUP_END'; |
||
146 | |||
147 | /** |
||
148 | * Singleton instance of FirePHP |
||
149 | * |
||
150 | * @var FirePHP |
||
151 | */ |
||
152 | protected static $instance = null; |
||
153 | |||
154 | /** |
||
155 | * Flag whether we are logging from within the exception handler |
||
156 | * |
||
157 | * @var boolean |
||
158 | */ |
||
159 | protected $inExceptionHandler = false; |
||
160 | |||
161 | /** |
||
162 | * Flag whether to throw PHP errors that have been converted to ErrorExceptions |
||
163 | * |
||
164 | * @var boolean |
||
165 | */ |
||
166 | protected $throwErrorExceptions = true; |
||
167 | |||
168 | /** |
||
169 | * Flag whether to convert PHP assertion errors to Exceptions |
||
170 | * |
||
171 | * @var boolean |
||
172 | */ |
||
173 | protected $convertAssertionErrorsToExceptions = true; |
||
174 | |||
175 | /** |
||
176 | * Flag whether to throw PHP assertion errors that have been converted to Exceptions |
||
177 | * |
||
178 | * @var boolean |
||
179 | */ |
||
180 | protected $throwAssertionExceptions = false; |
||
181 | |||
182 | /** |
||
183 | * Wildfire protocol message index |
||
184 | * |
||
185 | * @var int |
||
186 | */ |
||
187 | protected $messageIndex = 1; |
||
188 | |||
189 | /** |
||
190 | * Options for the library |
||
191 | * |
||
192 | * @var array |
||
193 | */ |
||
194 | protected $options = array('maxObjectDepth' => 10, |
||
195 | 'maxArrayDepth' => 20, |
||
196 | 'useNativeJsonEncode' => true, |
||
197 | 'includeLineNumbers' => true); |
||
198 | |||
199 | /** |
||
200 | * Filters used to exclude object members when encoding |
||
201 | * |
||
202 | * @var array |
||
203 | */ |
||
204 | protected $objectFilters = array(); |
||
205 | |||
206 | /** |
||
207 | * A stack of objects used to detect recursion during object encoding |
||
208 | * |
||
209 | * @var object |
||
210 | */ |
||
211 | protected $objectStack = array(); |
||
212 | |||
213 | /** |
||
214 | * Flag to enable/disable logging |
||
215 | * |
||
216 | * @var boolean |
||
217 | */ |
||
218 | protected $enabled = true; |
||
219 | |||
220 | /** |
||
221 | * The object constructor |
||
222 | */ |
||
223 | function __construct() { |
||
225 | |||
226 | /** |
||
227 | * When the object gets serialized only include specific object members. |
||
228 | * |
||
229 | * @return array |
||
230 | */ |
||
231 | public function __sleep() { |
||
234 | |||
235 | /** |
||
236 | * Gets singleton instance of FirePHP |
||
237 | * |
||
238 | * @param boolean $AutoCreate |
||
239 | * @return FirePHP |
||
240 | */ |
||
241 | public static function getInstance($AutoCreate=false) { |
||
247 | |||
248 | /** |
||
249 | * Creates FirePHP object and stores it for singleton access |
||
250 | * |
||
251 | * @return FirePHP |
||
252 | */ |
||
253 | public static function init() { |
||
256 | |||
257 | /** |
||
258 | * Enable and disable logging to Firebug |
||
259 | * |
||
260 | * @param boolean $Enabled TRUE to enable, FALSE to disable |
||
261 | * @return void |
||
262 | */ |
||
263 | public function setEnabled($Enabled) { |
||
266 | |||
267 | /** |
||
268 | * Check if logging is enabled |
||
269 | * |
||
270 | * @return boolean TRUE if enabled |
||
271 | */ |
||
272 | public function getEnabled() { |
||
275 | |||
276 | /** |
||
277 | * Specify a filter to be used when encoding an object |
||
278 | * |
||
279 | * Filters are used to exclude object members. |
||
280 | * |
||
281 | * @param string $Class The class name of the object |
||
282 | * @param array $Filter An array of members to exclude |
||
283 | * @return void |
||
284 | */ |
||
285 | public function setObjectFilter($Class, $Filter) { |
||
288 | |||
289 | /** |
||
290 | * Set some options for the library |
||
291 | * |
||
292 | * Options: |
||
293 | * - maxObjectDepth: The maximum depth to traverse objects (default: 10) |
||
294 | * - maxArrayDepth: The maximum depth to traverse arrays (default: 20) |
||
295 | * - useNativeJsonEncode: If true will use json_encode() (default: true) |
||
296 | * - includeLineNumbers: If true will include line numbers and filenames (default: true) |
||
297 | * |
||
298 | * @param array $Options The options to be set |
||
299 | * @return void |
||
300 | */ |
||
301 | public function setOptions($Options) { |
||
304 | |||
305 | /** |
||
306 | * Get options from the library |
||
307 | * |
||
308 | * @return array The currently set options |
||
309 | */ |
||
310 | public function getOptions() { |
||
313 | |||
314 | /** |
||
315 | * Register FirePHP as your error handler |
||
316 | * |
||
317 | * Will throw exceptions for each php error. |
||
318 | * |
||
319 | * @return mixed Returns a string containing the previously defined error handler (if any) |
||
320 | */ |
||
321 | public function registerErrorHandler($throwErrorExceptions=true) |
||
332 | |||
333 | /** |
||
334 | * FirePHP's error handler |
||
335 | * |
||
336 | * Throws exception for each php error that will occur. |
||
337 | * |
||
338 | * @param int $errno |
||
339 | * @param string $errstr |
||
340 | * @param string $errfile |
||
341 | * @param int $errline |
||
342 | * @param array $errcontext |
||
343 | */ |
||
344 | public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) |
||
361 | |||
362 | /** |
||
363 | * Register FirePHP as your exception handler |
||
364 | * |
||
365 | * @return mixed Returns the name of the previously defined exception handler, |
||
366 | * or NULL on error. |
||
367 | * If no previous handler was defined, NULL is also returned. |
||
368 | */ |
||
369 | public function registerExceptionHandler() |
||
373 | |||
374 | /** |
||
375 | * FirePHP's exception handler |
||
376 | * |
||
377 | * Logs all exceptions to your firebug console and then stops the script. |
||
378 | * |
||
379 | * @param Exception $Exception |
||
380 | * @throws Exception |
||
381 | */ |
||
382 | function exceptionHandler($Exception) { |
||
392 | |||
393 | /** |
||
394 | * Register FirePHP driver as your assert callback |
||
395 | * |
||
396 | * @param boolean $convertAssertionErrorsToExceptions |
||
397 | * @param boolean $throwAssertionExceptions |
||
398 | * @return mixed Returns the original setting or FALSE on errors |
||
399 | */ |
||
400 | public function registerAssertionHandler($convertAssertionErrorsToExceptions=true, $throwAssertionExceptions=false) |
||
411 | |||
412 | /** |
||
413 | * FirePHP's assertion handler |
||
414 | * |
||
415 | * Logs all assertions to your firebug console and then stops the script. |
||
416 | * |
||
417 | * @param string $file File source of assertion |
||
418 | * @param int $line Line source of assertion |
||
419 | * @param mixed $code Assertion code |
||
420 | */ |
||
421 | public function assertionHandler($file, $line, $code) |
||
440 | |||
441 | /** |
||
442 | * Set custom processor url for FirePHP |
||
443 | * |
||
444 | * @param string $URL |
||
445 | */ |
||
446 | public function setProcessorUrl($URL) |
||
450 | |||
451 | /** |
||
452 | * Set custom renderer url for FirePHP |
||
453 | * |
||
454 | * @param string $URL |
||
455 | */ |
||
456 | public function setRendererUrl($URL) |
||
460 | |||
461 | /** |
||
462 | * Start a group for following messages. |
||
463 | * |
||
464 | * Options: |
||
465 | * Collapsed: [true|false] |
||
466 | * Color: [#RRGGBB|ColorName] |
||
467 | * |
||
468 | * @param string $Name |
||
469 | * @param array $Options OPTIONAL Instructions on how to log the group |
||
470 | * @return true |
||
471 | * @throws Exception |
||
472 | */ |
||
473 | public function group($Name, $Options=null) { |
||
490 | |||
491 | /** |
||
492 | * Ends a group you have started before |
||
493 | * |
||
494 | * @return true |
||
495 | * @throws Exception |
||
496 | */ |
||
497 | public function groupEnd() { |
||
500 | |||
501 | /** |
||
502 | * Log object with label to firebug console |
||
503 | * |
||
504 | * @see FirePHP::LOG |
||
505 | * @param mixes $Object |
||
506 | * @param string $Label |
||
507 | * @return true |
||
508 | * @throws Exception |
||
509 | */ |
||
510 | public function log($Object, $Label=null) { |
||
513 | |||
514 | /** |
||
515 | * Log object with label to firebug console |
||
516 | * |
||
517 | * @see FirePHP::INFO |
||
518 | * @param mixes $Object |
||
519 | * @param string $Label |
||
520 | * @return true |
||
521 | * @throws Exception |
||
522 | */ |
||
523 | public function info($Object, $Label=null) { |
||
526 | |||
527 | /** |
||
528 | * Log object with label to firebug console |
||
529 | * |
||
530 | * @see FirePHP::WARN |
||
531 | * @param mixes $Object |
||
532 | * @param string $Label |
||
533 | * @return true |
||
534 | * @throws Exception |
||
535 | */ |
||
536 | public function warn($Object, $Label=null) { |
||
539 | |||
540 | /** |
||
541 | * Log object with label to firebug console |
||
542 | * |
||
543 | * @see FirePHP::ERROR |
||
544 | * @param mixes $Object |
||
545 | * @param string $Label |
||
546 | * @return true |
||
547 | * @throws Exception |
||
548 | */ |
||
549 | public function error($Object, $Label=null) { |
||
552 | |||
553 | /** |
||
554 | * Dumps key and variable to firebug server panel |
||
555 | * |
||
556 | * @see FirePHP::DUMP |
||
557 | * @param string $Key |
||
558 | * @param mixed $Variable |
||
559 | * @return true |
||
560 | * @throws Exception |
||
561 | */ |
||
562 | public function dump($Key, $Variable) { |
||
565 | |||
566 | /** |
||
567 | * Log a trace in the firebug console |
||
568 | * |
||
569 | * @see FirePHP::TRACE |
||
570 | * @param string $Label |
||
571 | * @return true |
||
572 | * @throws Exception |
||
573 | */ |
||
574 | public function trace($Label) { |
||
577 | |||
578 | /** |
||
579 | * Log a table in the firebug console |
||
580 | * |
||
581 | * @see FirePHP::TABLE |
||
582 | * @param string $Label |
||
583 | * @param string $Table |
||
584 | * @return true |
||
585 | * @throws Exception |
||
586 | */ |
||
587 | public function table($Label, $Table) { |
||
590 | |||
591 | /** |
||
592 | * Check if FirePHP is installed on client |
||
593 | * |
||
594 | * @return boolean |
||
595 | */ |
||
596 | public function detectClientExtension() { |
||
604 | |||
605 | /** |
||
606 | * Log varible to Firebug |
||
607 | * |
||
608 | * @see http://www.firephp.org/Wiki/Reference/Fb |
||
609 | * @param mixed $Object The variable to be logged |
||
610 | * @return true Return TRUE if message was added to headers, FALSE otherwise |
||
611 | * @throws Exception |
||
612 | */ |
||
613 | public function fb($Object) { |
||
875 | |||
876 | /** |
||
877 | * Standardizes path for windows systems. |
||
878 | * |
||
879 | * @param string $Path |
||
880 | * @return string |
||
881 | */ |
||
882 | protected function _standardizePath($Path) { |
||
885 | |||
886 | /** |
||
887 | * Escape trace path for windows systems |
||
888 | * |
||
889 | * @param array $Trace |
||
890 | * @return array |
||
891 | */ |
||
892 | protected function _escapeTrace($Trace) { |
||
904 | |||
905 | /** |
||
906 | * Escape file information of trace for windows systems |
||
907 | * |
||
908 | * @param string $File |
||
909 | * @return string |
||
910 | */ |
||
911 | protected function _escapeTraceFile($File) { |
||
922 | |||
923 | /** |
||
924 | * Send header |
||
925 | * |
||
926 | * @param string $Name |
||
927 | * @param string_type $Value |
||
928 | */ |
||
929 | protected function setHeader($Name, $Value) { |
||
932 | |||
933 | /** |
||
934 | * Get user agent |
||
935 | * |
||
936 | * @return string|false |
||
937 | */ |
||
938 | protected function getUserAgent() { |
||
942 | |||
943 | /** |
||
944 | * Returns a new exception |
||
945 | * |
||
946 | * @param string $Message |
||
947 | * @return Exception |
||
948 | */ |
||
949 | protected function newException($Message) { |
||
952 | |||
953 | /** |
||
954 | * Encode an object into a JSON string |
||
955 | * |
||
956 | * Uses PHP's jeson_encode() if available |
||
957 | * |
||
958 | * @param object $Object The object to be encoded |
||
959 | * @return string The JSON string |
||
960 | */ |
||
961 | public function jsonEncode($Object, $skipObjectEncode=false) |
||
975 | |||
976 | /** |
||
977 | * Encodes a table by encoding each row and column with encodeObject() |
||
978 | * |
||
979 | * @param array $Table The table to be encoded |
||
980 | * @return array |
||
981 | */ |
||
982 | protected function encodeTable($Table) { |
||
1002 | |||
1003 | /** |
||
1004 | * Encodes an object including members with |
||
1005 | * protected and private visibility |
||
1006 | * |
||
1007 | * @param Object $Object The object to be encoded |
||
1008 | * @param int $Depth The current traversal depth |
||
1009 | * @return array All members of the object |
||
1010 | */ |
||
1011 | protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1) |
||
1142 | |||
1143 | /** |
||
1144 | * Returns true if $string is valid UTF-8 and false otherwise. |
||
1145 | * |
||
1146 | * @param mixed $str String to be tested |
||
1147 | * @return boolean |
||
1148 | */ |
||
1149 | protected static function is_utf8($str) { |
||
1174 | |||
1175 | /** |
||
1176 | * Converts to and from JSON format. |
||
1177 | * |
||
1178 | * JSON (JavaScript Object Notation) is a lightweight data-interchange |
||
1179 | * format. It is easy for humans to read and write. It is easy for machines |
||
1180 | * to parse and generate. It is based on a subset of the JavaScript |
||
1181 | * Programming Language, Standard ECMA-262 3rd Edition - December 1999. |
||
1182 | * This feature can also be found in Python. JSON is a text format that is |
||
1183 | * completely language independent but uses conventions that are familiar |
||
1184 | * to programmers of the C-family of languages, including C, C++, C#, Java, |
||
1185 | * JavaScript, Perl, TCL, and many others. These properties make JSON an |
||
1186 | * ideal data-interchange language. |
||
1187 | * |
||
1188 | * This package provides a simple encoder and decoder for JSON notation. It |
||
1189 | * is intended for use with client-side Javascript applications that make |
||
1190 | * use of HTTPRequest to perform server communication functions - data can |
||
1191 | * be encoded into JSON notation for use in a client-side javascript, or |
||
1192 | * decoded from incoming Javascript requests. JSON format is native to |
||
1193 | * Javascript, and can be directly eval()'ed with no further parsing |
||
1194 | * overhead |
||
1195 | * |
||
1196 | * All strings should be in ASCII or UTF-8 format! |
||
1197 | * |
||
1198 | * LICENSE: Redistribution and use in source and binary forms, with or |
||
1199 | * without modification, are permitted provided that the following |
||
1200 | * conditions are met: Redistributions of source code must retain the |
||
1201 | * above copyright notice, this list of conditions and the following |
||
1202 | * disclaimer. Redistributions in binary form must reproduce the above |
||
1203 | * copyright notice, this list of conditions and the following disclaimer |
||
1204 | * in the documentation and/or other materials provided with the |
||
1205 | * distribution. |
||
1206 | * |
||
1207 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
1208 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
1209 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
||
1210 | * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||
1211 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||
1212 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
||
1213 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
1214 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
||
1215 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
||
1216 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
||
1217 | * DAMAGE. |
||
1218 | * |
||
1219 | * @category |
||
1220 | * @package Services_JSON |
||
1221 | * @author Michal Migurski <[email protected]> |
||
1222 | * @author Matt Knapp <mdknapp[at]gmail[dot]com> |
||
1223 | * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com> |
||
1224 | * @author Christoph Dorn <[email protected]> |
||
1225 | * @copyright 2005 Michal Migurski |
||
1226 | * @version CVS: $Id: FirePHP.class.php 3187 2012-07-12 11:21:01Z ctrlaltca $ |
||
1227 | * @license http://www.opensource.org/licenses/bsd-license.php |
||
1228 | * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 |
||
1229 | */ |
||
1230 | |||
1231 | |||
1232 | /** |
||
1233 | * Keep a list of objects as we descend into the array so we can detect recursion. |
||
1234 | */ |
||
1235 | private $json_objectStack = array(); |
||
1236 | |||
1237 | |||
1238 | /** |
||
1239 | * convert a string from one UTF-8 char to one UTF-16 char |
||
1240 | * |
||
1241 | * Normally should be handled by mb_convert_encoding, but |
||
1242 | * provides a slower PHP-only method for installations |
||
1243 | * that lack the multibye string extension. |
||
1244 | * |
||
1245 | * @param string $utf8 UTF-8 character |
||
1246 | * @return string UTF-16 character |
||
1247 | * @access private |
||
1248 | */ |
||
1249 | private function json_utf82utf16($utf8) |
||
1281 | |||
1282 | /** |
||
1283 | * encodes an arbitrary variable into JSON format |
||
1284 | * |
||
1285 | * @param mixed $var any number, boolean, string, array, or object to be encoded. |
||
1286 | * see argument 1 to Services_JSON() above for array-parsing behavior. |
||
1287 | * if var is a strng, note that encode() always expects it |
||
1288 | * to be in ASCII or UTF-8 format! |
||
1289 | * |
||
1290 | * @return mixed JSON string representation of input var or an error if a problem occurs |
||
1291 | * @access public |
||
1292 | */ |
||
1293 | private function json_encode($var) |
||
1498 | |||
1499 | /** |
||
1500 | * array-walking function for use in generating JSON-formatted name-value pairs |
||
1501 | * |
||
1502 | * @param string $name name of key to use |
||
1503 | * @param mixed $value reference to an array element to be encoded |
||
1504 | * |
||
1505 | * @return string JSON-formatted name-value pair, like '"name":value' |
||
1506 | * @access private |
||
1507 | */ |
||
1508 | private function json_name_value($name, $value) |
||
1528 | } |
||
1529 |
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.