3  * Error Stack Implementation
 
   5  * This is an incredibly simple implementation of a very complex error handling
 
   6  * facility.  It contains the ability
 
   7  * to track multiple errors from multiple packages simultaneously.  In addition,
 
   8  * it can track errors of many levels, save data along with the error, context
 
   9  * information such as the exact file, line number, class and function that
 
  10  * generated the error, and if necessary, it can raise a traditional PEAR_Error.
 
  11  * It has built-in support for PEAR::Log, to log errors as they occur
 
  13  * Since version 0.2alpha, it is also possible to selectively ignore errors,
 
  14  * through the use of an error callback, see {@link pushCallback()}
 
  16  * Since version 0.3alpha, it is possible to specify the exception class
 
  17  * returned from {@link push()}
 
  19  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
 
  20  * still be done quite handily in an error callback or by manipulating the returned array
 
  22  * @package    PEAR_ErrorStack
 
  23  * @author     Greg Beaver <cellog@php.net>
 
  24  * @copyright  2004-2008 Greg Beaver
 
  25  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 
  26  * @version    CVS: $Id: ErrorStack.php 313023 2011-07-06 19:17:11Z dufuz $
 
  27  * @link       http://pear.php.net/package/PEAR_ErrorStack
 
  36  *  'package1' => PEAR_ErrorStack object,
 
  37  *  'package2' => PEAR_ErrorStack object,
 
  42  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
 
  44 $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
 
  47  * Global error callback (default)
 
  49  * This is only used if set to non-false.  * is the default callback for
 
  50  * all packages, whereas specific packages may set a default callback
 
  51  * for all instances, regardless of whether they are a singleton or not.
 
  53  * To exclude non-singletons, only set the local callback for the singleton
 
  54  * @see PEAR_ErrorStack::setDefaultCallback()
 
  56  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
 
  58 $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
 
  63  * Global Log object (default)
 
  65  * This is only used if set to non-false.  Use to set a default log object for
 
  66  * all stacks, regardless of instantiation order or location
 
  67  * @see PEAR_ErrorStack::setDefaultLogger()
 
  69  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
 
  71 $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
 
  74  * Global Overriding Callback
 
  76  * This callback will override any error callbacks that specific loggers have set.
 
  77  * Use with EXTREME caution
 
  78  * @see PEAR_ErrorStack::staticPushCallback()
 
  80  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
 
  82 $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
 
  85  * One of four possible return values from the error Callback
 
  86  * @see PEAR_ErrorStack::_errorCallback()
 
  89  * If this is returned, then the error will be both pushed onto the stack
 
  92 define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
 
  94  * If this is returned, then the error will only be pushed onto the stack,
 
  97 define('PEAR_ERRORSTACK_PUSH', 2);
 
  99  * If this is returned, then the error will only be logged, but not pushed
 
 100  * onto the error stack.
 
 102 define('PEAR_ERRORSTACK_LOG', 3);
 
 104  * If this is returned, then the error is completely ignored.
 
 106 define('PEAR_ERRORSTACK_IGNORE', 4);
 
 108  * If this is returned, then the error is logged and die() is called.
 
 110 define('PEAR_ERRORSTACK_DIE', 5);
 
 114  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
 
 115  * the singleton method.
 
 117 define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
 
 120  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
 
 121  * that has no __toString() method
 
 123 define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
 
 125  * Error Stack Implementation
 
 129  * // global error stack
 
 130  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
 
 131  * // local error stack
 
 132  * $local_stack = new PEAR_ErrorStack('MyPackage');
 
 134  * @author     Greg Beaver <cellog@php.net>
 
 136  * @package    PEAR_ErrorStack
 
 137  * @category   Debugging
 
 138  * @copyright  2004-2008 Greg Beaver
 
 139  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
 
 140  * @version    CVS: $Id: ErrorStack.php 313023 2011-07-06 19:17:11Z dufuz $
 
 141  * @link       http://pear.php.net/package/PEAR_ErrorStack
 
 143 class PEAR_ErrorStack {
 
 145      * Errors are stored in the order that they are pushed on the stack.
 
 146      * @since 0.4alpha Errors are no longer organized by error level.
 
 147      * This renders pop() nearly unusable, and levels could be more easily
 
 148      * handled in a callback anyway
 
 152     var $_errors = array();
 
 155      * Storage of errors by level.
 
 157      * Allows easy retrieval and deletion of only errors from a particular level
 
 158      * @since PEAR 1.4.0dev
 
 162     var $_errorsByLevel = array();
 
 165      * Package name this error stack represents
 
 172      * Determines whether a PEAR_Error is thrown upon every error addition
 
 176     var $_compat = false;
 
 179      * If set to a valid callback, this will be used to generate the error
 
 180      * message from the error code, otherwise the message passed in will be
 
 182      * @var false|string|array
 
 185     var $_msgCallback = false;
 
 188      * If set to a valid callback, this will be used to generate the error
 
 189      * context for an error.  For PHP-related errors, this will be a file
 
 190      * and line number as retrieved from debug_backtrace(), but can be
 
 191      * customized for other purposes.  The error might actually be in a separate
 
 192      * configuration file, or in a database query.
 
 193      * @var false|string|array
 
 196     var $_contextCallback = false;
 
 199      * If set to a valid callback, this will be called every time an error
 
 200      * is pushed onto the stack.  The return value will be used to determine
 
 201      * whether to allow an error to be pushed or logged.
 
 203      * The return value must be one an PEAR_ERRORSTACK_* constant
 
 204      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
 
 205      * @var false|string|array
 
 208     var $_errorCallback = array();
 
 211      * PEAR::Log object for logging errors
 
 215     var $_logger = false;
 
 218      * Error messages - designed to be overridden
 
 222     var $_errorMsgs = array();
 
 225      * Set up a new error stack
 
 227      * @param string   $package name of the package this error stack represents
 
 228      * @param callback $msgCallback callback used for error message generation
 
 229      * @param callback $contextCallback callback used for context generation,
 
 230      *                 defaults to {@link getFileLine()}
 
 231      * @param boolean  $throwPEAR_Error
 
 233     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
 
 234                          $throwPEAR_Error = false)
 
 236         $this->_package = $package;
 
 237         $this->setMessageCallback($msgCallback);
 
 238         $this->setContextCallback($contextCallback);
 
 239         $this->_compat = $throwPEAR_Error;
 
 243      * Return a single error stack for this package.
 
 245      * Note that all parameters are ignored if the stack for package $package
 
 246      * has already been instantiated
 
 247      * @param string   $package name of the package this error stack represents
 
 248      * @param callback $msgCallback callback used for error message generation
 
 249      * @param callback $contextCallback callback used for context generation,
 
 250      *                 defaults to {@link getFileLine()}
 
 251      * @param boolean  $throwPEAR_Error
 
 252      * @param string   $stackClass class to instantiate
 
 254      * @return PEAR_ErrorStack
 
 256     function &singleton($package, $msgCallback = false, $contextCallback = false,
 
 257                          $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
 
 259         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
 
 260             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
 
 262         if (!class_exists($stackClass)) {
 
 263             if (function_exists('debug_backtrace')) {
 
 264                 $trace = debug_backtrace();
 
 266             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
 
 267                 'exception', array('stackclass' => $stackClass),
 
 268                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
 
 271         $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
 
 272             new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
 
 274         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
 
 278      * Internal error handler for PEAR_ErrorStack class
 
 280      * Dies if the error is an exception (and would have died anyway)
 
 283     function _handleError($err)
 
 285         if ($err['level'] == 'exception') {
 
 286             $message = $err['message'];
 
 287             if (isset($_SERVER['REQUEST_URI'])) {
 
 292             var_dump($err['context']);
 
 298      * Set up a PEAR::Log object for all error stacks that don't have one
 
 302     function setDefaultLogger(&$log)
 
 304         if (is_object($log) && method_exists($log, 'log') ) {
 
 305             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
 
 306         } elseif (is_callable($log)) {
 
 307             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
 
 312      * Set up a PEAR::Log object for this error stack
 
 315     function setLogger(&$log)
 
 317         if (is_object($log) && method_exists($log, 'log') ) {
 
 318             $this->_logger = &$log;
 
 319         } elseif (is_callable($log)) {
 
 320             $this->_logger = &$log;
 
 325      * Set an error code => error message mapping callback
 
 327      * This method sets the callback that can be used to generate error
 
 328      * messages for any instance
 
 329      * @param array|string Callback function/method
 
 331     function setMessageCallback($msgCallback)
 
 334             $this->_msgCallback = array(&$this, 'getErrorMessage');
 
 336             if (is_callable($msgCallback)) {
 
 337                 $this->_msgCallback = $msgCallback;
 
 343      * Get an error code => error message mapping callback
 
 345      * This method returns the current callback that can be used to generate error
 
 347      * @return array|string|false Callback function/method or false if none
 
 349     function getMessageCallback()
 
 351         return $this->_msgCallback;
 
 355      * Sets a default callback to be used by all error stacks
 
 357      * This method sets the callback that can be used to generate error
 
 358      * messages for a singleton
 
 359      * @param array|string Callback function/method
 
 360      * @param string Package name, or false for all packages
 
 363     function setDefaultCallback($callback = false, $package = false)
 
 365         if (!is_callable($callback)) {
 
 368         $package = $package ? $package : '*';
 
 369         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
 
 373      * Set a callback that generates context information (location of error) for an error stack
 
 375      * This method sets the callback that can be used to generate context
 
 376      * information for an error.  Passing in NULL will disable context generation
 
 377      * and remove the expensive call to debug_backtrace()
 
 378      * @param array|string|null Callback function/method
 
 380     function setContextCallback($contextCallback)
 
 382         if ($contextCallback === null) {
 
 383             return $this->_contextCallback = false;
 
 385         if (!$contextCallback) {
 
 386             $this->_contextCallback = array(&$this, 'getFileLine');
 
 388             if (is_callable($contextCallback)) {
 
 389                 $this->_contextCallback = $contextCallback;
 
 395      * Set an error Callback
 
 396      * If set to a valid callback, this will be called every time an error
 
 397      * is pushed onto the stack.  The return value will be used to determine
 
 398      * whether to allow an error to be pushed or logged.
 
 400      * The return value must be one of the ERRORSTACK_* constants.
 
 402      * This functionality can be used to emulate PEAR's pushErrorHandling, and
 
 403      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
 
 404      * the error stack or logging
 
 405      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
 
 407      * @param string|array $cb
 
 409     function pushCallback($cb)
 
 411         array_push($this->_errorCallback, $cb);
 
 415      * Remove a callback from the error callback stack
 
 416      * @see pushCallback()
 
 417      * @return array|string|false
 
 419     function popCallback()
 
 421         if (!count($this->_errorCallback)) {
 
 424         return array_pop($this->_errorCallback);
 
 428      * Set a temporary overriding error callback for every package error stack
 
 430      * Use this to temporarily disable all existing callbacks (can be used
 
 431      * to emulate the @ operator, for instance)
 
 432      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
 
 433      * @see staticPopCallback(), pushCallback()
 
 434      * @param string|array $cb
 
 437     function staticPushCallback($cb)
 
 439         array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
 
 443      * Remove a temporary overriding error callback
 
 444      * @see staticPushCallback()
 
 445      * @return array|string|false
 
 448     function staticPopCallback()
 
 450         $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
 
 451         if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
 
 452             $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
 
 458      * Add an error to the stack
 
 460      * If the message generator exists, it is called with 2 parameters.
 
 461      *  - the current Error Stack object
 
 462      *  - an array that is in the same format as an error.  Available indices
 
 463      *    are 'code', 'package', 'time', 'params', 'level', and 'context'
 
 465      * Next, if the error should contain context information, this is
 
 466      * handled by the context grabbing method.
 
 467      * Finally, the error is pushed onto the proper error stack
 
 468      * @param int    $code      Package-specific error code
 
 469      * @param string $level     Error level.  This is NOT spell-checked
 
 470      * @param array  $params    associative array of error parameters
 
 471      * @param string $msg       Error message, or a portion of it if the message
 
 473      * @param array  $repackage If this error re-packages an error pushed by
 
 474      *                          another package, place the array returned from
 
 475      *                          {@link pop()} in this parameter
 
 476      * @param array  $backtrace Protected parameter: use this to pass in the
 
 477      *                          {@link debug_backtrace()} that should be used
 
 478      *                          to find error context
 
 479      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
 
 480      * thrown.  If a PEAR_Error is returned, the userinfo
 
 481      * property is set to the following array:
 
 486      *    'params' => $params,
 
 487      *    'package' => $this->_package,
 
 490      *    'context' => $context,
 
 492      * //['repackage' => $err] repackaged error array/Exception class
 
 496      * Normally, the previous array is returned.
 
 498     function push($code, $level = 'error', $params = array(), $msg = false,
 
 499                   $repackage = false, $backtrace = false)
 
 502         // grab error context
 
 503         if ($this->_contextCallback) {
 
 505                 $backtrace = debug_backtrace();
 
 507             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
 
 511         $time = explode(' ', microtime());
 
 512         $time = $time[1] + $time[0];
 
 516                 'package' => $this->_package,
 
 519                 'context' => $context,
 
 524             $err['repackage'] = $repackage;
 
 527         // set up the error message, if necessary
 
 528         if ($this->_msgCallback) {
 
 529             $msg = call_user_func_array($this->_msgCallback,
 
 530                                         array(&$this, $err));
 
 531             $err['message'] = $msg;
 
 535         // try the overriding callback first
 
 536         $callback = $this->staticPopCallback();
 
 538             $this->staticPushCallback($callback);
 
 540         if (!is_callable($callback)) {
 
 541             // try the local callback next
 
 542             $callback = $this->popCallback();
 
 543             if (is_callable($callback)) {
 
 544                 $this->pushCallback($callback);
 
 546                 // try the default callback
 
 547                 $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
 
 548                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
 
 549                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
 
 552         if (is_callable($callback)) {
 
 553             switch(call_user_func($callback, $err)){
 
 554                 case PEAR_ERRORSTACK_IGNORE: 
 
 557                 case PEAR_ERRORSTACK_PUSH: 
 
 560                 case PEAR_ERRORSTACK_LOG: 
 
 563                 case PEAR_ERRORSTACK_DIE: 
 
 566                 // anything else returned has the same effect as pushandlog
 
 570             array_unshift($this->_errors, $err);
 
 571             if (!isset($this->_errorsByLevel[$err['level']])) {
 
 572                 $this->_errorsByLevel[$err['level']] = array();
 
 574             $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
 
 577             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
 
 584         if ($this->_compat && $push) {
 
 585             return $this->raiseError($msg, $code, null, null, $err);
 
 591      * Static version of {@link push()}
 
 593      * @param string $package   Package name this error belongs to
 
 594      * @param int    $code      Package-specific error code
 
 595      * @param string $level     Error level.  This is NOT spell-checked
 
 596      * @param array  $params    associative array of error parameters
 
 597      * @param string $msg       Error message, or a portion of it if the message
 
 599      * @param array  $repackage If this error re-packages an error pushed by
 
 600      *                          another package, place the array returned from
 
 601      *                          {@link pop()} in this parameter
 
 602      * @param array  $backtrace Protected parameter: use this to pass in the
 
 603      *                          {@link debug_backtrace()} that should be used
 
 604      *                          to find error context
 
 605      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
 
 606      *                          thrown.  see docs for {@link push()}
 
 609     function staticPush($package, $code, $level = 'error', $params = array(),
 
 610                         $msg = false, $repackage = false, $backtrace = false)
 
 612         $s = &PEAR_ErrorStack::singleton($package);
 
 613         if ($s->_contextCallback) {
 
 615                 if (function_exists('debug_backtrace')) {
 
 616                     $backtrace = debug_backtrace();
 
 620         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
 
 624      * Log an error using PEAR::Log
 
 625      * @param array $err Error array
 
 626      * @param array $levels Error level => Log constant map
 
 631         if ($this->_logger) {
 
 632             $logger = &$this->_logger;
 
 634             $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
 
 636         if (is_a($logger, 'Log')) {
 
 638                 'exception' => PEAR_LOG_CRIT,
 
 639                 'alert' => PEAR_LOG_ALERT,
 
 640                 'critical' => PEAR_LOG_CRIT,
 
 641                 'error' => PEAR_LOG_ERR,
 
 642                 'warning' => PEAR_LOG_WARNING,
 
 643                 'notice' => PEAR_LOG_NOTICE,
 
 644                 'info' => PEAR_LOG_INFO,
 
 645                 'debug' => PEAR_LOG_DEBUG);
 
 646             if (isset($levels[$err['level']])) {
 
 647                 $level = $levels[$err['level']];
 
 649                 $level = PEAR_LOG_INFO;
 
 651             $logger->log($err['message'], $level, $err);
 
 652         } else { // support non-standard logs
 
 653             call_user_func($logger, $err);
 
 659      * Pop an error off of the error stack
 
 661      * @return false|array
 
 662      * @since 0.4alpha it is no longer possible to specify a specific error
 
 663      * level to return - the last error pushed will be returned, instead
 
 667         $err = @array_shift($this->_errors);
 
 668         if (!is_null($err)) {
 
 669             @array_pop($this->_errorsByLevel[$err['level']]);
 
 670             if (!count($this->_errorsByLevel[$err['level']])) {
 
 671                 unset($this->_errorsByLevel[$err['level']]);
 
 678      * Pop an error off of the error stack, static method
 
 680      * @param string package name
 
 684     function staticPop($package)
 
 687             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
 
 690             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
 
 695      * Determine whether there are any errors on the stack
 
 696      * @param string|array Level name.  Use to determine if any errors
 
 697      * of level (string), or levels (array) have been pushed
 
 700     function hasErrors($level = false)
 
 703             return isset($this->_errorsByLevel[$level]);
 
 705         return count($this->_errors);
 
 709      * Retrieve all errors since last purge
 
 711      * @param boolean set in order to empty the error stack
 
 712      * @param string level name, to return only errors of a particular severity
 
 715     function getErrors($purge = false, $level = false)
 
 719                 if (!isset($this->_errorsByLevel[$level])) {
 
 722                     return $this->_errorsByLevel[$level];
 
 725                 return $this->_errors;
 
 729             $ret = $this->_errorsByLevel[$level];
 
 730             foreach ($this->_errorsByLevel[$level] as $i => $unused) {
 
 731                 // entries are references to the $_errors array
 
 732                 $this->_errorsByLevel[$level][$i] = false;
 
 734             // array_filter removes all entries === false
 
 735             $this->_errors = array_filter($this->_errors);
 
 736             unset($this->_errorsByLevel[$level]);
 
 739         $ret = $this->_errors;
 
 740         $this->_errors = array();
 
 741         $this->_errorsByLevel = array();
 
 746      * Determine whether there are any errors on a single error stack, or on any error stack
 
 748      * The optional parameter can be used to test the existence of any errors without the need of
 
 749      * singleton instantiation
 
 750      * @param string|false Package name to check for errors
 
 751      * @param string Level name to check for a particular severity
 
 755     function staticHasErrors($package = false, $level = false)
 
 758             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
 
 761             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
 
 763         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
 
 764             if ($obj->hasErrors($level)) {
 
 772      * Get a list of all errors since last purge, organized by package
 
 773      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
 
 774      * @param boolean $purge Set to purge the error stack of existing errors
 
 775      * @param string  $level Set to a level name in order to retrieve only errors of a particular level
 
 776      * @param boolean $merge Set to return a flat array, not organized by package
 
 777      * @param array   $sortfunc Function used to sort a merged array - default
 
 778      *        sorts by time, and should be good for most cases
 
 782     function staticGetErrors($purge = false, $level = false, $merge = false,
 
 783                              $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
 
 786         if (!is_callable($sortfunc)) {
 
 787             $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
 
 789         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
 
 790             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
 
 793                     $ret = array_merge($ret, $test);
 
 795                     $ret[$package] = $test;
 
 800             usort($ret, $sortfunc);
 
 806      * Error sorting function, sorts by time
 
 809     function _sortErrors($a, $b)
 
 811         if ($a['time'] == $b['time']) {
 
 814         if ($a['time'] < $b['time']) {
 
 821      * Standard file/line number/function/class context callback
 
 823      * This function uses a backtrace generated from {@link debug_backtrace()}
 
 824      * and so will not work at all in PHP < 4.3.0.  The frame should
 
 825      * reference the frame that contains the source of the error.
 
 826      * @return array|false either array('file' => file, 'line' => line,
 
 827      *         'function' => function name, 'class' => class name) or
 
 828      *         if this doesn't work, then false
 
 830      * @param integer backtrace frame.
 
 831      * @param array Results of debug_backtrace()
 
 834     function getFileLine($code, $params, $backtrace = null)
 
 836         if ($backtrace === null) {
 
 841         if (!isset($backtrace[1])) {
 
 844             while (isset($backtrace[$functionframe]['function']) &&
 
 845                   $backtrace[$functionframe]['function'] == 'eval' &&
 
 846                   isset($backtrace[$functionframe + 1])) {
 
 850         if (isset($backtrace[$frame])) {
 
 851             if (!isset($backtrace[$frame]['file'])) {
 
 854             $funcbacktrace = $backtrace[$functionframe];
 
 855             $filebacktrace = $backtrace[$frame];
 
 856             $ret = array('file' => $filebacktrace['file'],
 
 857                          'line' => $filebacktrace['line']);
 
 858             // rearrange for eval'd code or create function errors
 
 859             if (strpos($filebacktrace['file'], '(') && 
 
 860                   preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
 
 862                 $ret['file'] = $matches[1];
 
 863                 $ret['line'] = $matches[2] + 0;
 
 865             if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
 
 866                 if ($funcbacktrace['function'] != 'eval') {
 
 867                     if ($funcbacktrace['function'] == '__lambda_func') {
 
 868                         $ret['function'] = 'create_function() code';
 
 870                         $ret['function'] = $funcbacktrace['function'];
 
 874             if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
 
 875                 $ret['class'] = $funcbacktrace['class'];
 
 883      * Standard error message generation callback
 
 885      * This method may also be called by a custom error message generator
 
 886      * to fill in template values from the params array, simply
 
 887      * set the third parameter to the error message template string to use
 
 889      * The special variable %__msg% is reserved: use it only to specify
 
 890      * where a message passed in by the user should be placed in the template,
 
 893      * Error message: %msg% - internal error
 
 895      * If the message passed like so:
 
 898      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
 
 901      * The returned error message will be "Error message: server error 500 -
 
 903      * @param PEAR_ErrorStack
 
 905      * @param string|false Pre-generated error message template
 
 909     function getErrorMessage(&$stack, $err, $template = false)
 
 912             $mainmsg = $template;
 
 914             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
 
 916         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
 
 917         if (is_array($err['params']) && count($err['params'])) {
 
 918             foreach ($err['params'] as $name => $val) {
 
 919                 if (is_array($val)) {
 
 920                     // @ is needed in case $val is a multi-dimensional array
 
 921                     $val = @implode(', ', $val);
 
 923                 if (is_object($val)) {
 
 924                     if (method_exists($val, '__toString')) {
 
 925                         $val = $val->__toString();
 
 927                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
 
 928                             'warning', array('obj' => get_class($val)),
 
 929                             'object %obj% passed into getErrorMessage, but has no __toString() method');
 
 933                 $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
 
 940      * Standard Error Message Template generator from code
 
 943     function getErrorMessageTemplate($code)
 
 945         if (!isset($this->_errorMsgs[$code])) {
 
 948         return $this->_errorMsgs[$code];
 
 952      * Set the Error Message Template array
 
 954      * The array format must be:
 
 956      * array(error code => 'message template',...)
 
 959      * Error message parameters passed into {@link push()} will be used as input
 
 960      * for the error message.  If the template is 'message %foo% was %bar%', and the
 
 961      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
 
 962      * be 'message one was six'
 
 965     function setErrorMessageTemplate($template)
 
 967         $this->_errorMsgs = $template;
 
 972      * emulate PEAR::raiseError()
 
 976     function raiseError()
 
 978         require_once 'PEAR.php';
 
 979         $args = func_get_args();
 
 980         return call_user_func_array(array('PEAR', 'raiseError'), $args);
 
 983 $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
 
 984 $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));