root/trunk/patErrorManager.php

Revision 46 (checked in by schst, 1 month ago)

Get rid of global variables by replacing them with static properties

  • Property 0 set to
  • Property 1 set to
Line 
1 <?php
2 /**
3  * patErrorManager main error management class used by pat tools for the
4  * application-internal error management. Creates patError objects for
5  * any errors for precise error management.
6  *
7  * $Id$
8  *
9  * @package    patError
10  */
11
12 /**
13  * error definition: illegal options.
14  */
15 define('PATERRORMANAGER_ERROR_ILLEGAL_OPTIONS', 1);
16
17 /**
18  * error definition: callback function does not exist.
19  */
20 define('PATERRORMANAGER_ERROR_CALLBACK_NOT_CALLABLE', 2);
21
22 /**
23  * error definition: illegal error handling mode.
24  */
25 define('PATERRORMANAGER_ERROR_ILLEGAL_MODE', 3);
26
27 /**
28  * patErrorManager main error management class used by pat tools for the
29  * application-internal error management. Creates patError objects for
30  * any errors for precise error management.
31  *
32  * @static
33  * @package    patError
34  * @version    0.3
35  * @author    gERD Schaufelberger <gerd@php-tools.net>
36  * @author    Stephan Schmidt <schst@php-tools.net>
37  * @license    LGPL
38  * @link    http://www.php-tools.net
39  * @todo    implement ignoreError() to ignore errrors with a certain code
40  * @todo    implement expectError() to ignore an error with a certain code only once.
41  */
42 class patErrorManager
43 {
44     /**
45      * global definitions needed to keep track of things when calling the patErrorManager
46      * static methods.
47      */
48     protected static $errorHandling = array(
49                                             E_NOTICE    => array( 'mode' => 'echo' ),
50                                             E_WARNING    => array( 'mode' => 'echo' ),
51                                             E_ERROR        => array( 'mode' => 'die' )
52                                         );
53
54     /**
55       * available error levels
56       * Stored in a variable to keep them flexible
57       */
58     protected static $errorLevels = array(
59                                             E_NOTICE    => 'Notice',
60                                             E_WARNING   => 'Warning',
61                                             E_ERROR     => 'Error'
62                                         );
63     /**
64       * error class names
65      * Stored in a variable allows to change during runtime
66      */
67     protected static $errorClass = 'patError';
68
69     /**
70      * ignore errors
71      * Store error-codes that will be ignored forever
72      */
73     protected static $errorIgnores = array();
74     
75     /**
76      * expects errors
77      * Store error-codes that will be ignored once
78      */
79     protected static $errorExpects = array();
80     
81    /**
82     * method for checking whether the return value of a pat application method is a pat
83     * error object.
84     *
85     * @static
86     * @access    public
87     * @param    mixed    &$object
88     * @return    boolean $result    True if argument is a patError-object, false otherwise.
89     */
90     public static function isError($object) {
91         if (!is_object($object)) {
92             return false;
93         }
94
95         if (strtolower(get_class($object)) != strtolower(self::$errorClass) && !is_subclass_of($object, self::$errorClass)) {
96             return false;
97         }
98         return  true;
99     }
100
101    /**
102     * wrapper for the {@link raise()} method where you do not have to specify the
103     * error level - a {@link patError} object with error level E_ERROR will be returned.
104     *
105     * @static
106     * @access    public
107     * @param    string    $code    The application-internal error code for this error
108     * @param    string    $msg    The error message, which may also be shown the user if need be.
109     * @param    mixed    $info    Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
110     * @return    object    $error    The configured patError object
111     * @see        raise()
112     * @see        patError
113     */
114     public static function raiseError($code, $msg, $info = null) {
115         return patErrorManager::raise(E_ERROR, $code, $msg, $info);
116     }
117
118    /**
119     * wrapper for the {@link raise()} method where you do not have to specify the
120     * error level - a {@link patError} object with error level E_WARNING will be returned.
121     *
122     * @static
123     * @access    public
124     * @param    string    $code    The application-internal error code for this error
125     * @param    string    $msg    The error message, which may also be shown the user if need be.
126     * @param    mixed    $info    Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
127     * @return    object    $error    The configured patError object
128     * @see        raise()
129     * @see        patError
130     */
131     public static function raiseWarning($code, $msg, $info = null) {
132         return patErrorManager::raise(E_WARNING, $code, $msg, $info);
133     }
134
135    /**
136     * wrapper for the {@link raise()} method where you do not have to specify the
137     * error level - a {@link patError} object with error level E_NOTICE will be returned.
138     *
139     * @static
140     * @access    public
141     * @param    string    $code    The application-internal error code for this error
142     * @param    string    $msg    The error message, which may also be shown the user if need be.
143     * @param    mixed    $info    Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
144     * @return    object    $error    The configured patError object
145     * @see        raise()
146     * @see        patError
147     */
148     public static function raiseNotice($code, $msg, $info = null) {
149         return patErrorManager::raise(E_NOTICE, $code, $msg, $info);
150     }
151
152    /**
153     * creates a new patError object given the specified information.
154     *
155     * @access    public
156     * @param    int        $level    The error level - use any of PHP's own error levels for this: E_ERROR, E_WARNING, E_NOTICE, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE.
157     * @param    string    $code    The application-internal error code for this error
158     * @param    string    $msg    The error message, which may also be shown the user if need be.
159     * @param    mixed    $info    Optional: Additional error information (usually only developer-relevant information that the user should never see, like a database DSN).
160     * @return    mixed    $error    The configured patError object or false if this error should be ignored
161     * @see        patError
162     * @todo        implement 'simple' mode that returns just false (BC for patConfiguration)
163     * @todo        either remove HTML tags and entities from output or test for enviroment!!! <b></b> in shell is ugly!
164     */
165     public static function raise($level, $code, $msg, $info = null) {
166         // ignore this error?
167         if (in_array( $code, self::$errorIgnores)) {
168             return false;
169         }
170
171         // need patError
172         $class    =    self::$errorClass;
173         if (!class_exists($class, false)) {
174             include_once dirname(__FILE__) . '/'. $class .'.php';
175         }
176
177         // build error object
178         $error = new $class($level, $code, $msg, $info);
179
180         // this error was expected
181         if (!empty( self::$errorExpects)) {
182             $expected = array_pop(self::$errorExpects);
183             array_push(self::$errorExpects, $expected);
184             if (in_array( $code, $expected)) {
185                 return $error;
186             }
187         }
188
189         // see what to do with this kind of error
190         $handling = patErrorManager::getErrorHandling($level);
191
192         $function = 'handleError' . ucfirst($handling['mode']);
193         return patErrorManager::$function($error, $handling);
194     }
195
196    /**
197     * register a new error level
198     *
199     * This allows you to add custom error levels to the built-in
200     * - E_NOTICE
201     * - E_WARNING
202     * - E_NOTICE
203     *
204     * You may use this level in subsequent calls to raise().
205     * Error handling will be set to 'ignore' for the new level, you
206     * may change it by using setErrorHandling().
207     *
208     * You could be using PHP's predefined constants for error levels
209     * or any other integer value.
210     *
211     * @access    public
212     * @param    integer    error level
213     * @param    string    human-readable name
214     * @return    boolean    true on success; false if the level already has been registered
215     * @see        raise(), setErrorHandling()
216     * @link        http://www.php.net/manual/en/function.error-reporting.php
217     */
218     public static function registerErrorLevel($level, $name) {
219         if (isset(self::$errorLevels[$level])) {
220             return false;
221         }
222         self::$errorLevels[$level] = $name;
223         patErrorManager::setErrorHandling($level, 'ignore');
224         return true;
225     }
226
227    /**
228     * sets the way the patErrorManager will handle teh different error levels. Use this
229     * if you want to override the default settings.
230     *
231     * Error handling modes:
232     * - ignore
233     * - trigger
234     * - verbose
235     * - echo
236     * - callback
237     * - die
238     *
239     * You may also set the error handling for several modes at once using PHP's bit operations.
240     * Examples:
241     * - E_ALL = Set the handling for all levels
242     * - E_ERROR | E_WARNING = Set the handling for errors and warnings
243     * - E_ALL ^ E_ERROR = Set the handling for all levels except errors
244     *
245     * @static
246     * @access    public
247     * @param    int        $level        The error level for which to set the error handling
248     * @param    string    $mode        The mode to use for the error handling.
249     * @param    mixed    $options    Optional: Any options needed for the given mode.
250     * @return    mixed    $result        True on success, or a patError object if failed.
251     * @see        getErrorHandling()
252     */
253     public static function setErrorHandling($level, $mode, $options = null) {
254         $levels = self::$errorLevels;
255
256         $function = 'handleError' . ucfirst($mode);
257         if (!is_callable( array('patErrorManager', $function))) {
258             return patErrorManager::raiseError(E_ERROR,
259                                                 'patErrorManager:' . PATERRORMANAGER_ERROR_ILLEGAL_MODE,
260                                                 'Error Handling mode is not knwon',
261                                                 'Mode: ' $mode . ' is not implemented.'
262                                                 );
263         }
264
265         foreach ($levels as $eLevel => $eTitle) {
266             if (($level & $eLevel ) != $eLevel) {
267                 continue;
268             }
269
270             // set callback options
271             if ($mode == 'callback') {
272                 if (!is_array($options)) {
273                     return patErrorManager::raiseError(E_ERROR,
274                                                         'patErrorManager:' . PATERRORMANAGER_ERROR_ILLEGAL_OPTIONS,
275                                                         'Options for callback not valid'
276                                                         );
277                 }
278
279                 if (!is_callable($options)) {
280                     $tmp = array('GLOBAL');
281                     if (is_array($options)) {
282                         $tmp[0] = $options[0];
283                         $tmp[1] = $options[1];
284                     } else {
285                         $tmp[1] = $options;
286                     }
287
288                     return patErrorManager::raiseError(E_ERROR,
289                                                         'patErrorManager:' . PATERRORMANAGER_ERROR_CALLBACK_NOT_CALLABLE,
290                                                         'Function is not callable',
291                                                         'Function:' . $tmp[1]  . ' scope ' . $tmp[0] . '.'
292                                                         );
293                 }
294             }
295
296
297             // save settings
298             self::$errorHandling[$eLevel] = array('mode' => $mode);
299             if ($options != null) {
300                 self::$errorHandling[$eLevel]['options']= $options;
301             }
302         }
303         return  true;
304     }
305
306    /**
307     * retrieves the current error handling settings for the specified error level.
308     *
309     * @access    public
310     * @param    int        $level        The error level to retrieve. This can be any of PHP's own error levels, e.g. E_ALL, E_NOTICE...
311     * @return    array    $handling    All error handling details
312     */
313     public static function getErrorHandling($level) {
314         return self::$errorHandling[$level];
315     }
316
317    /**
318     * translate an error level
319     *
320     * returns the human-readable name for an error level,
321     * e.g. E_ERROR will be translated to 'Error'.
322     *
323     * @access    public
324     * @param    integer        error level
325     * @return    string        human-readable representation
326     */
327     public static function translateErrorLevel($level) {
328         if (isset(self::$errorLevels[$level])) {
329             return self::$errorLevels[$level];
330         }
331         return 'Unknown error level';
332     }
333
334    /**
335     * setErrorClass
336     *
337     * In order to autoload this class, the filename containing that class must be
338     * named like the class itself; with an appending ".php". Although the file must be stored
339     * in the same directory as patErrorManager.php (this file)
340     *
341     * @access public
342     * @param string $name classname
343     * @return boolean $result true on success
344     */
345     public static function setErrorClass($name) {
346         // include old error-class
347         if ($name !== self::$errorClass && !class_exists(self::$errorClass, false)) {
348             include_once dirname( __FILE__ ) . '/' . self::$errorClass . '.php';
349         }
350
351         self::$errorClass = $name;
352         return true;
353     }
354
355    /**
356     * add error codes to be ingored
357     *
358     * @static
359     * @access public
360     * @param mixed $codes either an array of error code or a single code that will be ignored in future
361     * @return boolean $result true on success
362     */
363     public static function addIgnore($codes) {
364         if (!is_array($codes)) {
365             $codes = array( $codes );
366         }
367
368         $codes = array_merge(self::$errorIgnores, $codes);
369         self::$errorIgnores = array_unique($codes);
370
371         return true;
372     }
373
374    /**
375     * removeIgnore
376     *
377     *
378     * @static
379     * @access public
380     * @return boolean $result true on success
381     */
382     public static function removeIgnore($codes) {
383         if (!is_array($codes)) {
384             $codes = array($codes);
385         }
386
387         foreach ($codes as $code) {
388             $index = array_search($code, self::$errorIgnores);
389             if ($index === false) {
390                 continue;
391             }
392
393             unset(self::$errorIgnores[$index]);
394         }
395
396         // reorder the codes
397         self::$errorIgnores = array_values(self::$errorIgnores);
398
399         return true;
400     }
401
402    /**
403     * recieve all registerd error codes that will be ignored
404     *
405     * @static
406     * @access public
407     * @return array $codes list of error codes
408     */
409     public static function getIgnore() {
410         return self::$errorIgnores;
411     }
412
413    /**
414     * empty list of errors to be ignored
415     *
416     * @static
417     * @access public
418     * @return boolean $result true on success
419     */
420     public static function clearIgnore() {
421         self::$errorIgnores = array();
422         return true;
423     }
424
425    /**
426     * add expected errors to stack
427     *
428     * @static
429     * @access public
430     * @param mixed $codes either an array of error code or a single code that will be ignored in future
431     * @return boolean $result true on success
432     */
433     public static function pushExpect($codes) {
434         if (!is_array($codes)) {
435             $codes = array( $codes );
436         }
437         array_push(self::$errorExpects, $codes);
438         return true;
439     }
440
441    /**
442     * remove top of error-codes from stack
443     *
444     * @static
445     * @access public
446     * @return boolean $result true on success
447     */
448     public static function popExpect() {
449         if (empty(self::$errorExpects)) {
450             return false;
451         }
452
453         array_pop(self::$errorExpects);
454         return true;
455     }
456
457    /**
458     * recieve all registerd error codes that will be ignored
459     *
460     * @static
461     * @access public
462     * @return array $codes list of error codes
463     */
464     public static function getExpect() {
465         return self::$errorExpects;
466     }
467
468    /**
469     * empty list of errors to be ignored
470     *
471     * @static
472     * @access public
473     * @return boolean $result true on success
474     */
475     public static function clearExpect() {
476         self::$errorExpects = array();
477         return true;
478     }
479
480    /**
481     * handleError: Ignore
482     * Does nothing
483     *
484     * @access private
485     * @param object $error patError-Object
486     * @param array $options options for handler
487     * @return object $error error-object
488     * @see raise()
489     */
490     public static function handleErrorIgnore($error, $options) {
491         return $error;
492     }
493
494    /**
495     * handleError: Echo
496     * display error message
497     *
498     * @access private
499     * @param object $error patError-Object
500     * @param array $options options for handler
501     * @return object $error error-object
502     * @see raise()
503     */
504     public static function handleErrorEcho($error, $options) {
505         $level_human = patErrorManager::translateErrorLevel( $error->getLevel() );
506
507         if (isset($_SERVER['HTTP_HOST'])) {
508             // output as html
509             echo "<br /><b>pat-$level_human</b>: " . $error->getMessage() . "<br />\n";
510         } else {
511             // output as simple text
512             if (defined( 'STDERR')) {
513                 fwrite(STDERR, "pat-$level_human: " . $error->getMessage() . "\n");
514             } else {
515                 echo "pat-$level_human: " . $error->getMessage() . "\n";
516             }
517         }
518         return $error;
519     }
520
521    /**
522     * handleError: Verbose
523     * display verbose output for developing purpose
524     *
525     * @access private
526     * @param object $error patError-Object
527     * @param array $options options for handler
528     * @return object $error error-object
529     * @see raise()
530     */
531     public static function handleErrorVerbose($error, $options) {
532         $level_human = patErrorManager::translateErrorLevel($error->getLevel());
533         $info = $error->getInfo();
534
535         if (isset($_SERVER['HTTP_HOST'])) {
536             // output as html
537             echo "<br /><b>pat-$level_human</b>: " . $error->getMessage() . "<br />\n";
538             if ($info != null) {
539                 echo "&nbsp;&nbsp;&nbsp;" . $error->getInfo() . "<br />\n";
540             }
541         } else {
542             // output as simple text
543             echo "pat-$level_human: " . $error->getMessage() . "\n";
544             if ($info != null) {
545                 echo "    " . $error->getInfo() . "\n";
546             }
547         }
548         return $error;
549     }
550
551    /**
552     * handleError: die
553     * display error-message and die
554     *
555     * @access private
556     * @param object $error patError-Object
557     * @param array $options options for handler
558     * @return object $error error-object
559     * @see raise()
560     */
561     public static function handleErrorDie( $error, $options )
562     {
563         $level_human = patErrorManager::translateErrorLevel($error->getLevel());
564
565         if (isset($_SERVER['HTTP_HOST'])) {
566             // output as html
567             die("<br /><b>pat-$level_human</b> " . $error->getMessage() . "<br />\n");
568         } else {
569             // output as simple text
570             if (defined('STDERR')) {
571                 fwrite(STDERR, "pat-$level_human " . $error->getMessage() . "\n");
572                 die();
573             } else {
574                 die("pat-$level_human " . $error->getMessage() . "\n");
575             }
576         }
577         return $error;
578     }
579
580    /**
581     * handleError: trigger
582     * trigger php-error
583     *
584     * @access private
585     * @param object $error patError-Object
586     * @param array $options options for handler
587     * @return object $error error-object
588     * @see raise()
589     */
590     public static function handleErrorTrigger($error, $options) {
591         switch ($error->getLevel()) {
592             case E_NOTICE:
593                 $level = E_USER_NOTICE;
594                 break;
595             case E_WARNING:
596                 $level = E_USER_WARNING;
597                 break;
598             case E_NOTICE:
599                 $level = E_NOTICE;
600                 break;
601             default:
602                 $level = E_USER_ERROR;
603                 break;
604         }
605
606         trigger_error($error->getMessage(), $level);
607         return $error;
608     }
609
610    /**
611     * handleError: callback
612     * forward error to custom handler
613     *
614     * @access private
615     * @param object $error patError-Object
616     * @param array $options options for handler
617     * @return object $error error-object
618     * @see raise()
619     */
620     public static function handleErrorCallback($error, $options) {
621