Total Complexity | 101 |
Total Lines | 690 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like PEAR 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.
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 PEAR, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
84 | class PEAR |
||
85 | { |
||
86 | /** |
||
87 | * Whether to enable internal debug messages. |
||
88 | * |
||
89 | * @var bool |
||
90 | * @access private |
||
91 | */ |
||
92 | public $_debug = false; |
||
93 | |||
94 | /** |
||
95 | * Default error mode for this object. |
||
96 | * |
||
97 | * @var int |
||
98 | * @access private |
||
99 | */ |
||
100 | public $_default_error_mode = null; |
||
101 | |||
102 | /** |
||
103 | * Default error options used for this object when error mode |
||
104 | * is PEAR_ERROR_TRIGGER. |
||
105 | * |
||
106 | * @var int |
||
107 | * @access private |
||
108 | */ |
||
109 | public $_default_error_options = null; |
||
110 | |||
111 | /** |
||
112 | * Default error handler (callback) for this object, if error mode is |
||
113 | * PEAR_ERROR_CALLBACK. |
||
114 | * |
||
115 | * @var string |
||
116 | * @access private |
||
117 | */ |
||
118 | public $_default_error_handler = ''; |
||
119 | |||
120 | /** |
||
121 | * Which class to use for error objects. |
||
122 | * |
||
123 | * @var string |
||
124 | * @access private |
||
125 | */ |
||
126 | public $_error_class = 'PEAR_Error'; |
||
127 | |||
128 | /** |
||
129 | * An array of expected errors. |
||
130 | * |
||
131 | * @var array |
||
132 | * @access private |
||
133 | */ |
||
134 | public $_expected_errors = array(); |
||
135 | |||
136 | /** |
||
137 | * List of methods that can be called both statically and non-statically. |
||
138 | * @var array |
||
139 | */ |
||
140 | protected static $bivalentMethods = array( |
||
141 | 'setErrorHandling' => true, |
||
142 | 'raiseError' => true, |
||
143 | 'throwError' => true, |
||
144 | 'pushErrorHandling' => true, |
||
145 | 'popErrorHandling' => true, |
||
146 | ); |
||
147 | |||
148 | /** |
||
149 | * Constructor. Registers this object in |
||
150 | * $_PEAR_destructor_object_list for destructor emulation if a |
||
151 | * destructor object exists. |
||
152 | * |
||
153 | * @param string $error_class (optional) which class to use for |
||
154 | * error objects, defaults to PEAR_Error. |
||
155 | * @access public |
||
156 | * @return void |
||
157 | */ |
||
158 | public function __construct($error_class = null) |
||
159 | { |
||
160 | $classname = strtolower(get_class($this)); |
||
161 | if ($this->_debug) { |
||
162 | print "PEAR constructor called, class=$classname\n"; |
||
163 | } |
||
164 | |||
165 | if ($error_class !== null) { |
||
166 | $this->_error_class = $error_class; |
||
167 | } |
||
168 | |||
169 | while ($classname && strcasecmp($classname, "pear")) { |
||
170 | $destructor = "_$classname"; |
||
171 | if (method_exists($this, $destructor)) { |
||
172 | global $_PEAR_destructor_object_list; |
||
173 | $_PEAR_destructor_object_list[] = $this; |
||
174 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { |
||
175 | register_shutdown_function("_PEAR_call_destructors"); |
||
176 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; |
||
177 | } |
||
178 | break; |
||
179 | } else { |
||
180 | $classname = get_parent_class($classname); |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Only here for backwards compatibility. |
||
187 | * E.g. Archive_Tar calls $this->PEAR() in its constructor. |
||
188 | * |
||
189 | * @param string $error_class Which class to use for error objects, |
||
190 | * defaults to PEAR_Error. |
||
191 | */ |
||
192 | public function PEAR($error_class = null) |
||
193 | { |
||
194 | self::__construct($error_class); |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * Destructor (the emulated type of...). Does nothing right now, |
||
199 | * but is included for forward compatibility, so subclass |
||
200 | * destructors should always call it. |
||
201 | * |
||
202 | * See the note in the class desciption about output from |
||
203 | * destructors. |
||
204 | * |
||
205 | * @access public |
||
206 | * @return void |
||
207 | */ |
||
208 | public function _PEAR() |
||
209 | { |
||
210 | if ($this->_debug) { |
||
211 | printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); |
||
212 | } |
||
213 | } |
||
214 | |||
215 | public function __call($method, $arguments) |
||
216 | { |
||
217 | if (!isset(self::$bivalentMethods[$method])) { |
||
218 | trigger_error( |
||
219 | 'Call to undefined method PEAR::' . $method . '()', |
||
220 | E_USER_ERROR |
||
221 | ); |
||
222 | } |
||
223 | return call_user_func_array( |
||
224 | array(get_class(), '_' . $method), |
||
225 | array_merge(array($this), $arguments) |
||
226 | ); |
||
227 | } |
||
228 | |||
229 | public static function __callStatic($method, $arguments) |
||
230 | { |
||
231 | if (!isset(self::$bivalentMethods[$method])) { |
||
232 | trigger_error( |
||
233 | 'Call to undefined method PEAR::' . $method . '()', |
||
234 | E_USER_ERROR |
||
235 | ); |
||
236 | } |
||
237 | return call_user_func_array( |
||
238 | array(get_class(), '_' . $method), |
||
239 | array_merge(array(null), $arguments) |
||
240 | ); |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * If you have a class that's mostly/entirely static, and you need static |
||
245 | * properties, you can use this method to simulate them. Eg. in your method(s) |
||
246 | * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); |
||
247 | * You MUST use a reference, or they will not persist! |
||
248 | * |
||
249 | * @param string $class The calling classname, to prevent clashes |
||
250 | * @param string $var The variable to retrieve. |
||
251 | * @return mixed A reference to the variable. If not set it will be |
||
252 | * auto initialised to NULL. |
||
253 | */ |
||
254 | public static function &getStaticProperty($class, $var) |
||
255 | { |
||
256 | static $properties; |
||
257 | if (!isset($properties[$class])) { |
||
258 | $properties[$class] = array(); |
||
259 | } |
||
260 | |||
261 | if (!array_key_exists($var, $properties[$class])) { |
||
262 | $properties[$class][$var] = null; |
||
263 | } |
||
264 | |||
265 | return $properties[$class][$var]; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Use this function to register a shutdown method for static |
||
270 | * classes. |
||
271 | * |
||
272 | * @param mixed $func The function name (or array of class/method) to call |
||
273 | * @param mixed $args The arguments to pass to the function |
||
274 | * |
||
275 | * @return void |
||
276 | */ |
||
277 | public static function registerShutdownFunc($func, $args = array()) |
||
278 | { |
||
279 | // if we are called statically, there is a potential |
||
280 | // that no shutdown func is registered. Bug #6445 |
||
281 | if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { |
||
282 | register_shutdown_function("_PEAR_call_destructors"); |
||
283 | $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; |
||
284 | } |
||
285 | $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Tell whether a value is a PEAR error. |
||
290 | * |
||
291 | * @param mixed $data the value to test |
||
292 | * @param int $code if $data is an error object, return true |
||
293 | * only if $code is a string and |
||
294 | * $obj->getMessage() == $code or |
||
295 | * $code is an integer and $obj->getCode() == $code |
||
296 | * |
||
297 | * @return bool true if parameter is an error |
||
298 | */ |
||
299 | public static function isError($data, $code = null) |
||
300 | { |
||
301 | if (!is_a($data, 'PEAR_Error')) { |
||
302 | return false; |
||
303 | } |
||
304 | |||
305 | if (is_null($code)) { |
||
306 | return true; |
||
307 | } elseif (is_string($code)) { |
||
308 | return $data->getMessage() == $code; |
||
309 | } |
||
310 | |||
311 | return $data->getCode() == $code; |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * Sets how errors generated by this object should be handled. |
||
316 | * Can be invoked both in objects and statically. If called |
||
317 | * statically, setErrorHandling sets the default behaviour for all |
||
318 | * PEAR objects. If called in an object, setErrorHandling sets |
||
319 | * the default behaviour for that object. |
||
320 | * |
||
321 | * @param object $object |
||
322 | * Object the method was called on (non-static mode) |
||
323 | * |
||
324 | * @param int $mode |
||
325 | * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
||
326 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
||
327 | * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. |
||
328 | * |
||
329 | * @param mixed $options |
||
330 | * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one |
||
331 | * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
||
332 | * |
||
333 | * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected |
||
334 | * to be the callback function or method. A callback |
||
335 | * function is a string with the name of the function, a |
||
336 | * callback method is an array of two elements: the element |
||
337 | * at index 0 is the object, and the element at index 1 is |
||
338 | * the name of the method to call in the object. |
||
339 | * |
||
340 | * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is |
||
341 | * a printf format string used when printing the error |
||
342 | * message. |
||
343 | * |
||
344 | * @access public |
||
345 | * @return void |
||
346 | * @see PEAR_ERROR_RETURN |
||
347 | * @see PEAR_ERROR_PRINT |
||
348 | * @see PEAR_ERROR_TRIGGER |
||
349 | * @see PEAR_ERROR_DIE |
||
350 | * @see PEAR_ERROR_CALLBACK |
||
351 | * @see PEAR_ERROR_EXCEPTION |
||
352 | * |
||
353 | * @since PHP 4.0.5 |
||
354 | */ |
||
355 | protected static function _setErrorHandling( |
||
356 | $object, |
||
357 | $mode = null, |
||
358 | $options = null |
||
359 | ) { |
||
360 | if ($object !== null) { |
||
361 | $setmode = &$object->_default_error_mode; |
||
362 | $setoptions = &$object->_default_error_options; |
||
363 | } else { |
||
364 | $setmode = &$GLOBALS['_PEAR_default_error_mode']; |
||
365 | $setoptions = &$GLOBALS['_PEAR_default_error_options']; |
||
366 | } |
||
367 | |||
368 | switch ($mode) { |
||
369 | case PEAR_ERROR_EXCEPTION: |
||
370 | case PEAR_ERROR_RETURN: |
||
371 | case PEAR_ERROR_PRINT: |
||
372 | case PEAR_ERROR_TRIGGER: |
||
373 | case PEAR_ERROR_DIE: |
||
374 | case null: |
||
375 | $setmode = $mode; |
||
376 | $setoptions = $options; |
||
377 | break; |
||
378 | |||
379 | case PEAR_ERROR_CALLBACK: |
||
380 | $setmode = $mode; |
||
381 | // class/object method callback |
||
382 | if (is_callable($options)) { |
||
383 | $setoptions = $options; |
||
384 | } else { |
||
385 | trigger_error("invalid error callback", E_USER_WARNING); |
||
386 | } |
||
387 | break; |
||
388 | |||
389 | default: |
||
390 | trigger_error("invalid error mode", E_USER_WARNING); |
||
391 | break; |
||
392 | } |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * This method is used to tell which errors you expect to get. |
||
397 | * Expected errors are always returned with error mode |
||
398 | * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, |
||
399 | * and this method pushes a new element onto it. The list of |
||
400 | * expected errors are in effect until they are popped off the |
||
401 | * stack with the popExpect() method. |
||
402 | * |
||
403 | * Note that this method can not be called statically |
||
404 | * |
||
405 | * @param mixed $code a single error code or an array of error codes to expect |
||
406 | * |
||
407 | * @return int the new depth of the "expected errors" stack |
||
408 | * @access public |
||
409 | */ |
||
410 | public function expectError($code = '*') |
||
411 | { |
||
412 | if (is_array($code)) { |
||
413 | array_push($this->_expected_errors, $code); |
||
414 | } else { |
||
415 | array_push($this->_expected_errors, array($code)); |
||
416 | } |
||
417 | return count($this->_expected_errors); |
||
418 | } |
||
419 | |||
420 | /** |
||
421 | * This method pops one element off the expected error codes |
||
422 | * stack. |
||
423 | * |
||
424 | * @return array the list of error codes that were popped |
||
425 | */ |
||
426 | public function popExpect() |
||
427 | { |
||
428 | return array_pop($this->_expected_errors); |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * This method checks unsets an error code if available |
||
433 | * |
||
434 | * @param mixed error code |
||
435 | * @return bool true if the error code was unset, false otherwise |
||
436 | * @access private |
||
437 | * @since PHP 4.3.0 |
||
438 | */ |
||
439 | public function _checkDelExpect($error_code) |
||
440 | { |
||
441 | $deleted = false; |
||
442 | foreach ($this->_expected_errors as $key => $error_array) { |
||
443 | if (in_array($error_code, $error_array)) { |
||
444 | unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); |
||
445 | $deleted = true; |
||
446 | } |
||
447 | |||
448 | // clean up empty arrays |
||
449 | if (0 == count($this->_expected_errors[$key])) { |
||
450 | unset($this->_expected_errors[$key]); |
||
451 | } |
||
452 | } |
||
453 | |||
454 | return $deleted; |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * This method deletes all occurrences of the specified element from |
||
459 | * the expected error codes stack. |
||
460 | * |
||
461 | * @param mixed $error_code error code that should be deleted |
||
462 | * @return mixed list of error codes that were deleted or error |
||
463 | * @access public |
||
464 | * @since PHP 4.3.0 |
||
465 | */ |
||
466 | public function delExpect($error_code) |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * This method is a wrapper that returns an instance of the |
||
492 | * configured error class with this object's default error |
||
493 | * handling applied. If the $mode and $options parameters are not |
||
494 | * specified, the object's defaults are used. |
||
495 | * |
||
496 | * @param mixed $message a text error message or a PEAR error object |
||
497 | * |
||
498 | * @param int $code a numeric error code (it is up to your class |
||
499 | * to define these if you want to use codes) |
||
500 | * |
||
501 | * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, |
||
502 | * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, |
||
503 | * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. |
||
504 | * |
||
505 | * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter |
||
506 | * specifies the PHP-internal error level (one of |
||
507 | * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). |
||
508 | * If $mode is PEAR_ERROR_CALLBACK, this |
||
509 | * parameter specifies the callback function or |
||
510 | * method. In other error modes this parameter |
||
511 | * is ignored. |
||
512 | * |
||
513 | * @param string $userinfo If you need to pass along for example debug |
||
514 | * information, this parameter is meant for that. |
||
515 | * |
||
516 | * @param string $error_class The returned error object will be |
||
517 | * instantiated from this class, if specified. |
||
518 | * |
||
519 | * @param bool $skipmsg If true, raiseError will only pass error codes, |
||
520 | * the error message parameter will be dropped. |
||
521 | * |
||
522 | * @return object a PEAR error object |
||
523 | * @see PEAR::setErrorHandling |
||
524 | * @since PHP 4.0.5 |
||
525 | */ |
||
526 | protected static function _raiseError( |
||
527 | $object, |
||
528 | $message = null, |
||
529 | $code = null, |
||
530 | $mode = null, |
||
531 | $options = null, |
||
532 | $userinfo = null, |
||
533 | $error_class = null, |
||
534 | $skipmsg = false |
||
535 | ) { |
||
536 | // The error is yet a PEAR error object |
||
537 | if (is_object($message)) { |
||
538 | $code = $message->getCode(); |
||
539 | $userinfo = $message->getUserInfo(); |
||
540 | $error_class = $message->getType(); |
||
541 | $message->error_message_prefix = ''; |
||
542 | $message = $message->getMessage(); |
||
543 | } |
||
544 | |||
545 | if ( |
||
546 | $object !== null && |
||
547 | isset($object->_expected_errors) && |
||
548 | count($object->_expected_errors) > 0 && |
||
549 | count($exp = end($object->_expected_errors)) |
||
550 | ) { |
||
551 | if ($exp[0] == "*" || |
||
552 | (is_int(reset($exp)) && in_array($code, $exp)) || |
||
553 | (is_string(reset($exp)) && in_array($message, $exp)) |
||
554 | ) { |
||
555 | $mode = PEAR_ERROR_RETURN; |
||
556 | } |
||
557 | } |
||
558 | |||
559 | // No mode given, try global ones |
||
560 | if ($mode === null) { |
||
561 | // Class error handler |
||
562 | if ($object !== null && isset($object->_default_error_mode)) { |
||
563 | $mode = $object->_default_error_mode; |
||
564 | $options = $object->_default_error_options; |
||
565 | // Global error handler |
||
566 | } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { |
||
567 | $mode = $GLOBALS['_PEAR_default_error_mode']; |
||
568 | $options = $GLOBALS['_PEAR_default_error_options']; |
||
569 | } |
||
570 | } |
||
571 | |||
572 | if ($error_class !== null) { |
||
573 | $ec = $error_class; |
||
574 | } elseif ($object !== null && isset($object->_error_class)) { |
||
575 | $ec = $object->_error_class; |
||
576 | } else { |
||
577 | $ec = 'PEAR_Error'; |
||
578 | } |
||
579 | |||
580 | if ($skipmsg) { |
||
581 | $a = new $ec($code, $mode, $options, $userinfo); |
||
582 | } else { |
||
583 | $a = new $ec($message, $code, $mode, $options, $userinfo); |
||
584 | } |
||
585 | |||
586 | return $a; |
||
587 | } |
||
588 | |||
589 | /** |
||
590 | * Simpler form of raiseError with fewer options. In most cases |
||
591 | * message, code and userinfo are enough. |
||
592 | * |
||
593 | * @param mixed $message a text error message or a PEAR error object |
||
594 | * |
||
595 | * @param int $code a numeric error code (it is up to your class |
||
596 | * to define these if you want to use codes) |
||
597 | * |
||
598 | * @param string $userinfo If you need to pass along for example debug |
||
599 | * information, this parameter is meant for that. |
||
600 | * |
||
601 | * @return object a PEAR error object |
||
602 | * @see PEAR::raiseError |
||
603 | */ |
||
604 | protected static function _throwError($object, $message = null, $code = null, $userinfo = null) |
||
613 | } |
||
614 | |||
615 | public static function staticPushErrorHandling($mode, $options = null) |
||
648 | } |
||
649 | |||
650 | public static function staticPopErrorHandling() |
||
684 | } |
||
685 | |||
686 | /** |
||
687 | * Push a new error handler on top of the error handler options stack. With this |
||
688 | * you can easily override the actual error handler for some code and restore |
||
689 | * it later with popErrorHandling. |
||
690 | * |
||
691 | * @param mixed $mode (same as setErrorHandling) |
||
692 | * @param mixed $options (same as setErrorHandling) |
||
693 | * |
||
694 | * @return bool Always true |
||
695 | * |
||
696 | * @see PEAR::setErrorHandling |
||
697 | */ |
||
698 | protected static function _pushErrorHandling($object, $mode, $options = null) |
||
717 | } |
||
718 | |||
719 | /** |
||
720 | * Pop the last error handler used |
||
721 | * |
||
722 | * @return bool Always true |
||
723 | * |
||
724 | * @see PEAR::pushErrorHandling |
||
725 | */ |
||
726 | protected static function _popErrorHandling($object) |
||
738 | } |
||
739 | |||
740 | /** |
||
741 | * OS independent PHP extension load. Remember to take care |
||
742 | * on the correct extension name for case sensitive OSes. |
||
743 | * |
||
744 | * @param string $ext The extension name |
||
745 | * @return bool Success or not on the dl() call |
||
746 | */ |
||
747 | public static function loadExtension($ext) |
||
774 | } |
||
775 | } |
||
776 | |||
1136 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.