PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/script/lib/PEAR/Exception.php

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