PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/include/PEAR/Exception.php

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