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