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 ?> |
