]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/PEAR/Exception.php
Merge branch '1.0.x' of gitorious.org:statusnet/mainline into inline-comments
[quix0rs-gnu-social.git] / extlib / PEAR / Exception.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
3 /**
4  * PEAR_Exception
5  *
6  * PHP versions 4 and 5
7  *
8  * LICENSE: This source file is subject to version 3.0 of the PHP license
9  * that is available through the world-wide-web at the following URI:
10  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
11  * the PHP License and are unable to obtain it through the web, please
12  * send a note to license@php.net so we can mail you a copy immediately.
13  *
14  * @category   pear
15  * @package    PEAR
16  * @author     Tomas V. V. Cox <cox@idecnet.com>
17  * @author     Hans Lellelid <hans@velum.net>
18  * @author     Bertrand Mansion <bmansion@mamasam.com>
19  * @author     Greg Beaver <cellog@php.net>
20  * @copyright  1997-2008 The PHP Group
21  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
22  * @version    CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $
23  * @link       http://pear.php.net/package/PEAR
24  * @since      File available since Release 1.3.3
25  */
26
27
28 /**
29  * Base PEAR_Exception Class
30  *
31  * 1) Features:
32  *
33  * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception))
34  * - Definable triggers, shot when exceptions occur
35  * - Pretty and informative error messages
36  * - Added more context info available (like class, method or cause)
37  * - cause can be a PEAR_Exception or an array of mixed
38  *   PEAR_Exceptions/PEAR_ErrorStack warnings
39  * - callbacks for specific exception classes and their children
40  *
41  * 2) Ideas:
42  *
43  * - Maybe a way to define a 'template' for the output
44  *
45  * 3) Inherited properties from PHP Exception Class:
46  *
47  * protected $message
48  * protected $code
49  * protected $line
50  * protected $file
51  * private   $trace
52  *
53  * 4) Inherited methods from PHP Exception Class:
54  *
55  * __clone
56  * __construct
57  * getMessage
58  * getCode
59  * getFile
60  * getLine
61  * getTraceSafe
62  * getTraceSafeAsString
63  * __toString
64  *
65  * 5) Usage example
66  *
67  * <code>
68  *  require_once 'PEAR/Exception.php';
69  *
70  *  class Test {
71  *     function foo() {
72  *         throw new PEAR_Exception('Error Message', ERROR_CODE);
73  *     }
74  *  }
75  *
76  *  function myLogger($pear_exception) {
77  *     echo $pear_exception->getMessage();
78  *  }
79  *  // each time a exception is thrown the 'myLogger' will be called
80  *  // (its use is completely optional)
81  *  PEAR_Exception::addObserver('myLogger');
82  *  $test = new Test;
83  *  try {
84  *     $test->foo();
85  *  } catch (PEAR_Exception $e) {
86  *     print $e;
87  *  }
88  * </code>
89  *
90  * @category   pear
91  * @package    PEAR
92  * @author     Tomas V.V.Cox <cox@idecnet.com>
93  * @author     Hans Lellelid <hans@velum.net>
94  * @author     Bertrand Mansion <bmansion@mamasam.com>
95  * @author     Greg Beaver <cellog@php.net>
96  * @copyright  1997-2008 The PHP Group
97  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
98  * @version    Release: 1.7.2
99  * @link       http://pear.php.net/package/PEAR
100  * @since      Class available since Release 1.3.3
101  *
102  */
103 class PEAR_Exception extends Exception
104 {
105     const OBSERVER_PRINT = -2;
106     const OBSERVER_TRIGGER = -4;
107     const OBSERVER_DIE = -8;
108     protected $cause;
109     private static $_observers = array();
110     private static $_uniqueid = 0;
111     private $_trace;
112
113     /**
114      * Supported signatures:
115      *  - PEAR_Exception(string $message);
116      *  - PEAR_Exception(string $message, int $code);
117      *  - PEAR_Exception(string $message, Exception $cause);
118      *  - PEAR_Exception(string $message, Exception $cause, int $code);
119      *  - PEAR_Exception(string $message, PEAR_Error $cause);
120      *  - PEAR_Exception(string $message, PEAR_Error $cause, int $code);
121      *  - PEAR_Exception(string $message, array $causes);
122      *  - PEAR_Exception(string $message, array $causes, int $code);
123      * @param string exception message
124      * @param int|Exception|PEAR_Error|array|null exception cause
125      * @param int|null exception code or null
126      */
127     public function __construct($message, $p2 = null, $p3 = null)
128     {
129         if (is_int($p2)) {
130             $code = $p2;
131             $this->cause = null;
132         } elseif (is_object($p2) || is_array($p2)) {
133             // using is_object allows both Exception and PEAR_Error
134             if (is_object($p2) && !($p2 instanceof Exception)) {
135                 if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) {
136                     throw new PEAR_Exception('exception cause must be Exception, ' .
137                         'array, or PEAR_Error');
138                 }
139             }
140             $code = $p3;
141             if (is_array($p2) && isset($p2['message'])) {
142                 // fix potential problem of passing in a single warning
143                 $p2 = array($p2);
144             }
145             $this->cause = $p2;
146         } else {
147             $code = null;
148             $this->cause = null;
149         }
150         parent::__construct($message, $code);
151         $this->signal();
152     }
153
154     /**
155      * @param mixed $callback  - A valid php callback, see php func is_callable()
156      *                         - A PEAR_Exception::OBSERVER_* constant
157      *                         - An array(const PEAR_Exception::OBSERVER_*,
158      *                           mixed $options)
159      * @param string $label    The name of the observer. Use this if you want
160      *                         to remove it later with removeObserver()
161      */
162     public static function addObserver($callback, $label = 'default')
163     {
164         self::$_observers[$label] = $callback;
165     }
166
167     public static function removeObserver($label = 'default')
168     {
169         unset(self::$_observers[$label]);
170     }
171
172     /**
173      * @return int unique identifier for an observer
174      */
175     public static function getUniqueId()
176     {
177         return self::$_uniqueid++;
178     }
179
180     private function signal()
181     {
182         foreach (self::$_observers as $func) {
183             if (is_callable($func)) {
184                 call_user_func($func, $this);
185                 continue;
186             }
187             settype($func, 'array');
188             switch ($func[0]) {
189                 case self::OBSERVER_PRINT :
190                     $f = (isset($func[1])) ? $func[1] : '%s';
191                     printf($f, $this->getMessage());
192                     break;
193                 case self::OBSERVER_TRIGGER :
194                     $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
195                     trigger_error($this->getMessage(), $f);
196                     break;
197                 case self::OBSERVER_DIE :
198                     $f = (isset($func[1])) ? $func[1] : '%s';
199                     die(printf($f, $this->getMessage()));
200                     break;
201                 default:
202                     trigger_error('invalid observer type', E_USER_WARNING);
203             }
204         }
205     }
206
207     /**
208      * Return specific error information that can be used for more detailed
209      * error messages or translation.
210      *
211      * This method may be overridden in child exception classes in order
212      * to add functionality not present in PEAR_Exception and is a placeholder
213      * to define API
214      *
215      * The returned array must be an associative array of parameter => value like so:
216      * <pre>
217      * array('name' => $name, 'context' => array(...))
218      * </pre>
219      * @return array
220      */
221     public function getErrorData()
222     {
223         return array();
224     }
225
226     /**
227      * Returns the exception that caused this exception to be thrown
228      * @access public
229      * @return Exception|array The context of the exception
230      */
231     public function getCause()
232     {
233         return $this->cause;
234     }
235
236     /**
237      * Function must be public to call on caused exceptions
238      * @param array
239      */
240     public function getCauseMessage(&$causes)
241     {
242         $trace = $this->getTraceSafe();
243         $cause = array('class'   => get_class($this),
244                        'message' => $this->message,
245                        'file' => 'unknown',
246                        'line' => 'unknown');
247         if (isset($trace[0])) {
248             if (isset($trace[0]['file'])) {
249                 $cause['file'] = $trace[0]['file'];
250                 $cause['line'] = $trace[0]['line'];
251             }
252         }
253         $causes[] = $cause;
254         if ($this->cause instanceof PEAR_Exception) {
255             $this->cause->getCauseMessage($causes);
256         } elseif ($this->cause instanceof Exception) {
257             $causes[] = array('class'   => get_class($this->cause),
258                               'message' => $this->cause->getMessage(),
259                               'file' => $this->cause->getFile(),
260                               'line' => $this->cause->getLine());
261         } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) {
262             $causes[] = array('class' => get_class($this->cause),
263                               'message' => $this->cause->getMessage(),
264                               'file' => 'unknown',
265                               'line' => 'unknown');
266         } elseif (is_array($this->cause)) {
267             foreach ($this->cause as $cause) {
268                 if ($cause instanceof PEAR_Exception) {
269                     $cause->getCauseMessage($causes);
270                 } elseif ($cause instanceof Exception) {
271                     $causes[] = array('class'   => get_class($cause),
272                                    'message' => $cause->getMessage(),
273                                    'file' => $cause->getFile(),
274                                    'line' => $cause->getLine());
275                 } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) {
276                     $causes[] = array('class' => get_class($cause),
277                                       'message' => $cause->getMessage(),
278                                       'file' => 'unknown',
279                                       'line' => 'unknown');
280                 } elseif (is_array($cause) && isset($cause['message'])) {
281                     // PEAR_ErrorStack warning
282                     $causes[] = array(
283                         'class' => $cause['package'],
284                         'message' => $cause['message'],
285                         'file' => isset($cause['context']['file']) ?
286                                             $cause['context']['file'] :
287                                             'unknown',
288                         'line' => isset($cause['context']['line']) ?
289                                             $cause['context']['line'] :
290                                             'unknown',
291                     );
292                 }
293             }
294         }
295     }
296
297     public function getTraceSafe()
298     {   
299         if (!isset($this->_trace)) {
300             $this->_trace = $this->getTrace();
301             if (empty($this->_trace)) {
302                 $backtrace = debug_backtrace();
303                 $this->_trace = array($backtrace[count($backtrace)-1]);
304             }
305         }
306         return $this->_trace;
307     }
308
309     public function getErrorClass()
310     {
311         $trace = $this->getTraceSafe();
312         return $trace[0]['class'];
313     }
314
315     public function getErrorMethod()
316     {
317         $trace = $this->getTraceSafe();
318         return $trace[0]['function'];
319     }
320
321     public function __toString()
322     {
323         if (isset($_SERVER['REQUEST_URI'])) {
324             return $this->toHtml();
325         }
326         return $this->toText();
327     }
328
329     public function toHtml()
330     {
331         $trace = $this->getTraceSafe();
332         $causes = array();
333         $this->getCauseMessage($causes);
334         $html =  '<table border="1" cellspacing="0">' . "\n";
335         foreach ($causes as $i => $cause) {
336             $html .= '<tr><td colspan="3" bgcolor="#ff9999">'
337                . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
338                . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
339                . 'on line <b>' . $cause['line'] . '</b>'
340                . "</td></tr>\n";
341         }
342         $html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
343                . '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
344                . '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
345                . '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
346
347         foreach ($trace as $k => $v) {
348             $html .= '<tr><td align="center">' . $k . '</td>'
349                    . '<td>';
350             if (!empty($v['class'])) {
351                 $html .= $v['class'] . $v['type'];
352             }
353             $html .= $v['function'];
354             $args = array();
355             if (!empty($v['args'])) {
356                 foreach ($v['args'] as $arg) {
357                     if (is_null($arg)) $args[] = 'null';
358                     elseif (is_array($arg)) $args[] = 'Array';
359                     elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
360                     elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
361                     elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
362                     else {
363                         $arg = (string)$arg;
364                         $str = htmlspecialchars(substr($arg, 0, 16));
365                         if (strlen($arg) > 16) $str .= '&hellip;';
366                         $args[] = "'" . $str . "'";
367                     }
368                 }
369             }
370             $html .= '(' . implode(', ',$args) . ')'
371                    . '</td>'
372                    . '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
373                    . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
374                    . '</td></tr>' . "\n";
375         }
376         $html .= '<tr><td align="center">' . ($k+1) . '</td>'
377                . '<td>{main}</td>'
378                . '<td>&nbsp;</td></tr>' . "\n"
379                . '</table>';
380         return $html;
381     }
382
383     public function toText()
384     {
385         $causes = array();
386         $this->getCauseMessage($causes);
387         $causeMsg = '';
388         foreach ($causes as $i => $cause) {
389             $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
390                    . $cause['message'] . ' in ' . $cause['file']
391                    . ' on line ' . $cause['line'] . "\n";
392         }
393         return $causeMsg . $this->getTraceAsString();
394     }
395 }
396
397 ?>