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