source: branches/version-2_13_0/data/module/PEAR/Exception.php @ 23125

Revision 23125, 13.7 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

Line 
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 313023 2011-07-06 19:17:11Z dufuz $
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.4
93 * @link       http://pear.php.net/package/PEAR
94 * @since      Class available since Release 1.3.3
95 *
96 */
97class 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']) . ' 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));
359                        if (strlen($arg) > 16) $str .= '&hellip;';
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>&nbsp;</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}
Note: See TracBrowser for help on using the repository browser.