home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / Raise.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  35.6 KB  |  920 lines

  1. <?php
  2. /**
  3.  * Error Management for PEAR
  4.  *
  5.  * The Error_Raise static class contains tremendously simple and powerful
  6.  * error management based on error codes.
  7.  * @package Error_Raise
  8.  * @author Greg Beaver <cellog@php.net>
  9.  * @version 0.2.2
  10.  */
  11. /**
  12.  * for PEAR_Error class
  13.  */
  14. require_once 'PEAR.php';
  15. /**
  16.  * Pre-defined Error classes for Error_Raise
  17.  */
  18. require_once 'HTML/Progress/Error/Raise/Error.php';
  19. /**
  20.  * Utility static class
  21.  */
  22. require_once 'HTML/Progress/Error/Util.php';
  23.  
  24. /**
  25.  * Repository for error message generations
  26.  * @see Error_Raise::setErrorMsgGenerator()
  27.  * @global array $GLOBALS['_ERROR_RAISE_MSGS']
  28.  * @name $_ERROR_RAISE_MSGS
  29.  * @access private
  30.  */
  31. $GLOBALS['_ERROR_RAISE_MSGS'] =
  32.     array(
  33.         'error_raise' => array('Error_Raise', '_getErrorMessage'),
  34.     );
  35.  
  36. /**
  37.  * Repository for context file/line number generators
  38.  *
  39.  * @see Error_Raise::setContextGrabber()
  40.  * @global array $GLOBALS['_ERROR_RAISE_CONTEXTGRABBER']
  41.  * @name $_ERROR_RAISE_CONTEXTGRABBER
  42.  * @access private
  43.  */
  44. $GLOBALS['_ERROR_RAISE_CONTEXTGRABBER'] =
  45.     array(
  46.         'error_raise' => array('Error_Util', '_getFileLine'),
  47.     );
  48.  
  49. /**
  50.  * Stack used to control error raising
  51.  *
  52.  * This stack contains disabled callbacks.  It is an array of either '*' for
  53.  * all callbacks, or an array of package names
  54.  * @see Error_Raise::disableErrorCallbacks()
  55.  * @access private
  56.  * @global array $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS']
  57.  * @name $_ERROR_RAISE_DISABLED_CALLBACKS
  58.  */
  59. $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'] = array();
  60. /**#@+
  61.  * Error message display constants
  62.  */
  63. /**
  64.  * Plain text error messages
  65.  */
  66. define('ERROR_RAISE_TEXT', 1);
  67. /**
  68.  * html error messages
  69.  */
  70. define('ERROR_RAISE_HTML', 2);
  71. /**
  72.  * ansi (console) error messages
  73.  */
  74. define('ERROR_RAISE_ANSI', 3);
  75. /**#@-*/
  76.  
  77. /**
  78.  * Error Raise - central coordination for generation of error messages
  79.  *
  80.  * To use, simply call Error_Raise::initialize() with the package name
  81.  * and a function name for generation of error messages.  There is no need
  82.  * to instantiate the Error_Raise or define any error classes, unless you
  83.  * need extra functionality in the error message context information (see
  84.  * {@link setContextGrabber()} for details).
  85.  *
  86.  * To create an error, you must:
  87.  * - define an error code
  88.  * - create a function that maps this error code to a message
  89.  * - call Error_Raise::initialize
  90.  * - call one of the error creators with the package name and any additional
  91.  *   parameters unique to this error instance
  92.  *
  93.  * If your package is named "mypackage", then create errors, warnings, notices,
  94.  * or exceptions by error code using Error_Raise::error('MyPackage', CODE),
  95.  * Error_Raise::warning('MyPackage', CODE), etc.  If you wish to use non-standard
  96.  * error types for your own debugging purposes like "debug" or "information",
  97.  * simply use {@link raise()} like Error_Raise::raise('MyPackage', CODE, 'debug');
  98.  *
  99.  * You can pass additional information in an associative array.
  100.  *
  101.  * <code>
  102.  * Error_Raise::notice('MyPackage', CODE,
  103.  *     array('name' => $aditional, 'otherstuff' => $another));
  104.  * </code>
  105.  *
  106.  * With this system, you can use {@link Error_Raise::sprintfErrorMessage()} in
  107.  * your error message generation function.
  108.  *
  109.  * The strength of this system is easy internationalization and other benefits.
  110.  * Different functions can be defined to return error messages, and even an
  111.  * end-user can define a different error-message generation function for their
  112.  * own purposes, without modification to the original source.
  113.  *
  114.  * In addition, unique error messages are generated for every package,
  115.  * guaranteed.  Used in conjunction with {@tutorial Error_Handler.pkg Error_Handler}, this can be
  116.  * used in more complicated packages and applications to handle errors from
  117.  * multiple packages, propagate errors and even transmute them, and log them or
  118.  * do other advanced processing.
  119.  *
  120.  * For those concerned about performance, all of this extra functionality is
  121.  * only 8% slower than the PEAR::raiseError() method.  In other words, the
  122.  * difference is negligible, and allows a huge jump in error handling.
  123.  * @see initialize()
  124.  * @tutorial Error_Raise.pkg
  125.  * @package Error_Raise
  126.  * @version 0.2.2
  127.  * @author Greg Beaver <cellog@php.net>
  128.  * @static
  129.  */
  130. class Error_Raise {
  131.     /**
  132.      * Initialize error raising for a package
  133.      *
  134.      * Use this method to assign an error message handler to a package.  Note:
  135.      * This is an alias to {@link set ErrorMsgGenerator()}
  136.      *
  137.      * As an example, here is a simple Error_Raise usage:
  138.      *
  139.      * <code>
  140.      * <?php
  141.      * // define error constants for package foo
  142.      * define("FOO_ERROR_NOT_NUMBER", 1);
  143.      * define("FOO_ERROR_NOT_STRING", 2);
  144.      *
  145.      * /**
  146.      *  * Error message generator for package Foo
  147.      *  {@*}
  148.      * function getFooMsg($code, $args, $state)
  149.      * {
  150.      *     $msgs = array(
  151.      *        FOO_ERROR_NOT_NUMBER => 'parameter %p% is a %type%, not a number',
  152.      *        FOO_ERROR_NOT_STRING => 'parameter %p% is a %type%, not a string',
  153.      *     );
  154.      *     if (isset($msgs[$code])) {
  155.      *         $message = $msgs[$code];
  156.      *     } else {
  157.      *         $message = 'Code ' . $code . ' is not a valid error code';
  158.      *     }
  159.      *     return Error_Raise::sprintfErrorMessageWithState(
  160.      *        $message, $args, $state);
  161.      * }
  162.      *
  163.      * // initialize error creation
  164.      * Error_Raise::initialize('foo', 'getFooMsg');
  165.      * // that's it!  Now you can do this any of these:
  166.      * Error_Raise::warning('foo', FOO_ERROR_NOT_STRING,
  167.      *    array('p' => 'bar', 'type' => 'object'));
  168.      * Error_Raise::notice('foo', FOO_ERROR_NOT_STRING,
  169.      *    array('p' => 'bar', 'type' => 'object'));
  170.      * Error_Raise::exception('foo', FOO_ERROR_NOT_NUMBER,
  171.      *    array('p' => 'bar', 'type' => 'object'));
  172.      * $e = Error_Raise::error('foo', FOO_ERROR_NOT_NUMBER,
  173.      *    array('p' => 'bar', 'type' => 'object'));
  174.      * echo $e->getMessage();
  175.      * // displays 'foo error : parameter bar is a object, not a number'
  176.      * echo $e->getMessage(ERROR_RAISE_HTML);
  177.      * // displays '<strong>foo error :</strong> parameter <strong>bar</strong>
  178.      * // is a <strong>object</strong>, not a number
  179.      * ?>
  180.      * </code>
  181.      * @param string package name
  182.      * @param array|string call_user_func_array-compatible function/method
  183.      *
  184.      *                     This function name can be either be a
  185.      *                     global function (string), static class method
  186.      *                     array(classname, method), or object method
  187.      *                     array(&$obj, method).  Be sure to assign by
  188.      *                     reference in PHP 4
  189.      * @static
  190.      */
  191.     function initialize($package, $errorMsgGenerator)
  192.     {
  193.         return Error_Raise::setErrorMsgGenerator($package, $errorMsgGenerator);
  194.     }
  195.     
  196.     /**
  197.      * Create a notice from the error code
  198.      * @param string package name
  199.      * @param integer error code
  200.      * @param array associative array of error-specific data.  This can be
  201.      *        anything.  When used with {@link sprintfErrorMessage()}, it will
  202.      *        allow extremely configurable error messages.
  203.      * @throws Error_Raise::ERROR_RAISE_ERROR_INVALID_INPUT
  204.      * @static
  205.      */
  206.     function notice($package, $code, $args = array())
  207.     {
  208.         /*                 validate input                  */
  209.         if (!is_int($code)) {
  210.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  211.                 array('var' => '$code',
  212.                       'was' => gettype($code),
  213.                       'expected' => 'int',
  214.                       'paramnum' => 2));
  215.         }
  216.         if (!is_string($package)) {
  217.             return Error_Raise::exception('error_raise',
  218.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  219.                 array('was' => gettype($package), 'expected' => 'string', 
  220.                       'param' => '$package', 'paramnum' => 1));
  221.         }
  222.         /*                 done validate input                  */
  223.         $packageclass = $package . '_error';
  224.         // create the error class if necessary
  225.         if (!class_exists($packageclass)) {
  226.             $packageclass = 'error_raise_error';
  227.         }
  228.         $mode = 0;
  229.         $extracallback = null;
  230.         if (isset($GLOBALS['_PEAR_default_error_mode']) &&
  231.               ($GLOBALS['_PEAR_default_error_mode'] & PEAR_ERROR_CALLBACK)) {
  232.             $mode |= $GLOBALS['_PEAR_default_error_mode'];
  233.             $extracallback = $GLOBALS['_PEAR_default_error_options'];
  234.         }
  235.         // verify that packages with disabled callbacks don't have
  236.         // PEAR_ERROR_CALLBACK or PEAR_ERROR_TRIGGER as part of the mode
  237.         if (!count($disabledCallbacks = $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  238.             if ($disabledCallbacks == '*') {
  239.                 $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  240.             } else {
  241.                 if (in_array(strtolower($package), $disabledCallbacks)) {
  242.                     $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  243.                 }
  244.             }
  245.         }
  246.         $backtrace = null;
  247.         if (function_exists('debug_backtrace')) {
  248.             $backtrace = debug_backtrace();
  249.         }
  250.         
  251.         return new $packageclass($package, 'notice', $code, $args, $mode,
  252.             $extracallback, $backtrace, false);
  253.     }
  254.  
  255.     /**
  256.      * Create a warning from the error code
  257.      * @param string package name
  258.      * @param integer error code
  259.      * @param array associative array of error-specific data.  This can be
  260.      *        anything.  When used with {@link sprintfErrorMessage()}, it will
  261.      *        allow extremely configurable error messages.
  262.      * @throws Error_Raise::ERROR_RAISE_ERROR_INVALID_INPUT
  263.      * @static
  264.      */
  265.     function warning($package, $code, $args = array())
  266.     {
  267.         /*                 validate input                  */
  268.         if (!is_int($code)) {
  269.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  270.                 array('var' => '$code',
  271.                       'was' => gettype($code),
  272.                       'expected' => 'int',
  273.                       'paramnum' => 2));
  274.         }
  275.         if (!is_string($package)) {
  276.             return Error_Raise::exception('error_raise',
  277.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  278.                 array('was' => gettype($package), 'expected' => 'string', 
  279.                       'param' => '$package', 'paramnum' => 1));
  280.         }
  281.         /*                 done validate input                  */
  282.         $packageclass = $package . '_error';
  283.         // use the existing error class if possible
  284.         if (!class_exists($packageclass)) {
  285.             $packageclass = 'error_raise_error';
  286.         }
  287.         $mode = 0;
  288.         $extracallback = null;
  289.         if (isset($GLOBALS['_PEAR_default_error_mode']) &&
  290.               ($GLOBALS['_PEAR_default_error_mode'] & PEAR_ERROR_CALLBACK)) {
  291.             $mode |= $GLOBALS['_PEAR_default_error_mode'];
  292.             $extracallback = $GLOBALS['_PEAR_default_error_options'];
  293.         }
  294.         // verify that packages with disabled callbacks don't have
  295.         // PEAR_ERROR_CALLBACK or PEAR_ERROR_TRIGGER as part of the mode
  296.         if (!count($disabledCallbacks = $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  297.             if ($disabledCallbacks == '*') {
  298.                 $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  299.             } else {
  300.                 if (in_array(strtolower($package), $disabledCallbacks)) {
  301.                     $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  302.                 }
  303.             }
  304.         }
  305.         $backtrace = null;
  306.         if (function_exists('debug_backtrace')) {
  307.             $backtrace = debug_backtrace();
  308.         }
  309.         
  310.         return new $packageclass($package, 'warning', $code, $args, $mode,
  311.             $extracallback, $backtrace, false);
  312.     }
  313.  
  314.     /**
  315.      * Create an error from the error code
  316.      * @param string package name
  317.      * @param integer error code
  318.      * @param array associative array of error-specific data.  This can be
  319.      *        anything.  When used with {@link sprintfErrorMessage()}, it will
  320.      *        allow extremely configurable error messages.
  321.      * @throws Error_Raise::ERROR_RAISE_ERROR_INVALID_INPUT
  322.      * @static
  323.      */
  324.     function error($package, $code, $args = array())
  325.     {
  326.         /*                 validate input                  */
  327.         if (!is_int($code)) {
  328.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  329.                 array('var' => '$code',
  330.                       'was' => gettype($code),
  331.                       'expected' => 'int',
  332.                       'paramnum' => 2));
  333.         }
  334.         if (!is_string($package)) {
  335.             return Error_Raise::exception('error_raise',
  336.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  337.                 array('was' => gettype($package), 'expected' => 'string', 
  338.                       'param' => '$package', 'paramnum' => 1));
  339.         }
  340.         /*                 done validate input                  */
  341.         $packageclass = $package . '_error';
  342.         // use the existing error class if possible
  343.         if (!class_exists($packageclass)) {
  344.             $packageclass = 'error_raise_error';
  345.         }
  346.         $mode = 0;
  347.         $extracallback = null;
  348.         if (isset($GLOBALS['_PEAR_default_error_mode']) &&
  349.               ($GLOBALS['_PEAR_default_error_mode'] & PEAR_ERROR_CALLBACK)) {
  350.             $mode |= $GLOBALS['_PEAR_default_error_mode'];
  351.             $extracallback = $GLOBALS['_PEAR_default_error_options'];
  352.         }
  353.         // verify that packages with disabled callbacks don't have
  354.         // PEAR_ERROR_CALLBACK or PEAR_ERROR_TRIGGER as part of the mode
  355.         if (!count($disabledCallbacks = $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  356.             if ($disabledCallbacks == '*') {
  357.                 $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  358.             } else {
  359.                 if (in_array(strtolower($package), $disabledCallbacks)) {
  360.                     $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  361.                 }
  362.             }
  363.         }
  364.         $backtrace = null;
  365.         if (function_exists('debug_backtrace')) {
  366.             $backtrace = debug_backtrace();
  367.         }
  368.         
  369.         return new $packageclass($package, 'error', $code, $args, $mode,
  370.             $extracallback, $backtrace, false);
  371.     }
  372.  
  373.     /**
  374.      * Create an exception from the error code
  375.      * @param string package name
  376.      * @param integer error code
  377.      * @param array associative array of error-specific data.  This can be
  378.      *        anything.  When used with {@link sprintfErrorMessage()}, it will
  379.      *        allow extremely configurable error messages.
  380.      * @throws Error_Raise::ERROR_RAISE_ERROR_INVALID_INPUT
  381.      * @static
  382.      */
  383.     function exception($package, $code, $args = array())
  384.     {
  385.         /*                 validate input                  */
  386.         if (!is_int($code)) {
  387.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  388.                 array('var' => '$code',
  389.                       'was' => gettype($code),
  390.                       'expected' => 'int',
  391.                       'paramnum' => 2));
  392.         }
  393.         if (!is_string($package)) {
  394.             return Error_Raise::exception('error_raise',
  395.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  396.                 array('was' => gettype($package), 'expected' => 'string', 
  397.                       'param' => '$package', 'paramnum' => 1));
  398.         }
  399.         /*                 done validate input                  */
  400.         $packageclass = $package . '_error';
  401.         // use the existing error class if possible
  402.         if (!class_exists($packageclass)) {
  403.             $packageclass = 'error_raise_error';
  404.         }
  405.         $mode = 0;
  406.         $extracallback = null;
  407.         if (isset($GLOBALS['_PEAR_default_error_mode']) &&
  408.               ($GLOBALS['_PEAR_default_error_mode'] & PEAR_ERROR_CALLBACK)) {
  409.             $mode |= $GLOBALS['_PEAR_default_error_mode'];
  410.             $extracallback = $GLOBALS['_PEAR_default_error_options'];
  411.         }
  412.         // verify that packages with disabled callbacks don't have
  413.         // PEAR_ERROR_CALLBACK or PEAR_ERROR_TRIGGER as part of the mode
  414.         if (!count($disabledCallbacks = $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  415.             if ($disabledCallbacks == '*') {
  416.                 $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  417.             } else {
  418.                 if (in_array(strtolower($package), $disabledCallbacks)) {
  419.                     $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  420.                 }
  421.             }
  422.         }
  423.         $backtrace = null;
  424.         if (function_exists('debug_backtrace')) {
  425.             $backtrace = debug_backtrace();
  426.         }
  427.         
  428.         return new $packageclass($package, 'exception', $code, $args, $mode,
  429.             $extracallback, $backtrace, false);
  430.     }
  431.     
  432.     /**
  433.      * Return an error object
  434.      *
  435.      * For more control, call this static function directly, otherwise use
  436.      * one of the shorthand methods.
  437.      * @param string package name throwing the error
  438.      * @param integer error code
  439.      * @param string error type
  440.      * @param false|Error_Raise_Error parent error, for cascading
  441.      * @param integer error mode, see {@link PEAR.php}
  442.      * @param string|array callback function for PEAR_ERROR_CALLBACK mode
  443.      * @return Error_Raise_Error
  444.      * @throws ERROR_RAISE_ERROR_INVALID_INPUT
  445.      * @static
  446.      */
  447.     function raise($package, $code, $errorType, $args, $mode = null,
  448.         $extracallback = null, $parent = false)
  449.     {
  450.         /*                 validate input                  */
  451.         if (!is_int($code)) {
  452.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  453.                 array('var' => '$code',
  454.                       'was' => gettype($code),
  455.                       'expected' => 'int',
  456.                       'paramnum' => 2));
  457.         }
  458.         if (!is_string($package)) {
  459.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  460.                 array('var' => '$package',
  461.                       'was' => gettype($package),
  462.                       'expected' => 'string',
  463.                       'paramnum' => 1));
  464.         }
  465.         if (!is_string($errorType)) {
  466.             return Error_Raise::exception('error_raise', ERROR_RAISE_ERROR_INVALID_INPUT,
  467.                 array('paramnum' => 3,
  468.                       'var' => '$errorType',
  469.                       'was' => gettype($errorType),
  470.                       'expected' => 'string'));
  471.         }
  472.         $errorType = strtolower($errorType);
  473.         /*                 done validate input                  */
  474.         // create the error class if necessary
  475.         $errorClass = $package . '_error';
  476.         // use the existing error class if possible
  477.         if (!class_exists($errorClass)) {
  478.             $errorClass = 'error_raise_error';
  479.         }
  480.         
  481.         if (isset($GLOBALS['_PEAR_default_error_mode']) &&
  482.               ($GLOBALS['_PEAR_default_error_mode'] & PEAR_ERROR_CALLBACK)) {
  483.             $mode |= $GLOBALS['_PEAR_default_error_mode'];
  484.             $extracallback = $GLOBALS['_PEAR_default_error_options'];
  485.         }
  486.         // verify that packages with disabled callbacks don't have
  487.         // PEAR_ERROR_CALLBACK or PEAR_ERROR_TRIGGER as part of the mode
  488.         if (count($disabledCallbacks = $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  489.             if ($disabledCallbacks == '*') {
  490.                 $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  491.             } else {
  492.                 if (in_array(strtolower($package), $disabledCallbacks)) {
  493.                     $mode &= ~(PEAR_ERROR_CALLBACK | PEAR_ERROR_TRIGGER);
  494.                 }
  495.             }
  496.         }
  497.         $backtrace = null;
  498.         if (function_exists('debug_backtrace')) {
  499.             $backtrace = debug_backtrace();
  500.         }
  501.         
  502.         return new $errorClass($package, $errorType, $code, $args, $mode,
  503.             $extracallback, $backtrace, false);
  504.     }
  505.     
  506.     /**
  507.      * Determine if an error was triggered by a package or group of packages
  508.      *
  509.      * This will trigger a PHP warning if parameters are invalid
  510.      * @param Error_Raise_Error
  511.      * @param string|array single package name, or list of package names
  512.      * @return boolean
  513.      */
  514.     function isPackageError($error, $package)
  515.     {
  516.         if (is_string($package)) {
  517.             $package = array(strtolower($package));
  518.         }
  519.         if (!is_a($error, 'Error_Raise_Error')) {
  520.             return false;
  521.         }
  522.         if (array_walk($package, create_function('&$s','$s = strtolower($s);'))) {
  523.             return in_array($error->_package, $package);
  524.         }
  525.         return false;
  526.     }
  527.     
  528.     /**
  529.      * Determine whether input is an error class with level "error"
  530.      *
  531.      * use PEAR::isError() to determine if a class is an error class.  This
  532.      * static method is only for determining the error level of a class
  533.      * @static
  534.      * @param mixed
  535.      * @return boolean true if $obj is an Error_Raise_Error and is type error
  536.      */
  537.     function isError($obj)
  538.     {
  539.         return is_a($obj, 'error_raise_error') && $obj->_type == 'error';
  540.     }
  541.     
  542.     
  543.     /**
  544.      * Determine whether input is an error class with level "exception"
  545.      *
  546.      * use PEAR::isError() to determine if a class is an error class.  This
  547.      * static method is only for determining the error level of a class
  548.      * @static
  549.      * @param mixed
  550.      * @return boolean true if $obj is an Error_Raise_Error and is type exception
  551.      */
  552.     function isException($obj)
  553.     {
  554.         return is_a($obj, 'error_raise_error') && $obj->_type == 'exception';
  555.     }
  556.     
  557.     
  558.     /**
  559.      * Determine whether input is an error class with level "notice"
  560.      *
  561.      * use PEAR::isError() to determine if a class is an error class.  This
  562.      * static method is only for determining the error level of a class
  563.      * @static
  564.      * @param mixed
  565.      * @return boolean true if $obj is an Error_Raise_Error and is type notice
  566.      */
  567.     function isNotice($obj)
  568.     {
  569.         return is_a($obj, 'error_raise_error') && $obj->_type == 'notice';
  570.     }
  571.     
  572.     
  573.     /**
  574.      * Determine whether input is an error class with level "warning"
  575.      *
  576.      * use PEAR::isError() to determine if a class is an error class.  This
  577.      * static method is only for determining the error level of a class
  578.      * @static
  579.      * @param mixed
  580.      * @return boolean true if $obj is an Error_Raise_Error and is type warning
  581.      */
  582.     function isWarning($obj)
  583.     {
  584.         return is_a($obj, 'error_raise_error') && $obj->_type == 'warning';
  585.     }
  586.     
  587.     /**
  588.      * Get the list of packages for which callbacks are temporarily disabled
  589.      *
  590.      * @see disableErrorCallbacks
  591.      * @return false|array|*
  592.      */
  593.     function getDisabledCallbacks()
  594.     {
  595.         if (!count($GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'])) {
  596.             return false;
  597.         }
  598.         return $GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS']
  599.             [count($GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS']) - 1];
  600.     }
  601.     
  602.     /**
  603.      * Temporarily disable any error callbacks/trigger_error.
  604.      *
  605.      * To temporarily disable callback functions in order to suppress any
  606.      * error reporting of internal errors, use this static method.  To
  607.      * selectively disable a short list of packages, and allow others to inform
  608.      * callbacks of their creation, pass in an array of the names of packages
  609.      * to disable errors for.
  610.      *
  611.      * This is similar to PEAR::expectError(), except that only global
  612.      * error-handling is affected
  613.      * @param array list of packages to disable error callbacks for
  614.      * @throws Error_Raise_Exception::ERROR_RAISE_ERROR_INVALID_INPUT
  615.      * @return true|Error_Raise_Exception
  616.      * @static
  617.      */
  618.     function disableErrorCallbacks($packages = array())
  619.     {
  620.         if (!is_array($packages) && !is_string($packages)) {
  621.             return Error_Raise::exception('error_raise',
  622.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  623.                 array('was' => gettype($packages), 'expected' => 'array|string',
  624.                       'param' => '$packages', 'paramnum' => 1));
  625.         }
  626.         if (is_string($packages)) {
  627.             $packages = array($packages);
  628.         }
  629.         $newpack = array();
  630.         foreach($packages as $i => $package) {
  631.             if (!is_string($package)) {
  632.                 return Error_Raise::exception('error_raise',
  633.                 ERROR_RAISE_ERROR_INVALID_INPUT,
  634.                 array('was' => gettype($package), 'expected' => 'string',
  635.                       'param' => '$packages[' . $i . ']', 'paramnum' => 1));
  636.             }
  637.             $newpack[] = strtolower($package);
  638.         }
  639.         if (!count($newpack)) {
  640.             array_push($GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'], '*');
  641.         } else {
  642.             array_push($GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS'], $newpack);
  643.         }
  644.         return true;
  645.     }
  646.     
  647.     /**
  648.      * Re-enable callbacks that were temporarily disabled with
  649.      * {@link disableErrorCallbacks()}
  650.      */
  651.     function reenableErrorCallbacks()
  652.     {
  653.         array_pop($GLOBALS['_ERROR_RAISE_DISABLED_CALLBACKS']);
  654.     }
  655.     
  656.     /**
  657.      * Change the error message generation method from one set in the
  658.      * constructor
  659.      *
  660.      * If later logic requires the use of different error messages for a
  661.      * package, use this static method to change the message generator.
  662.      * @return true|Error_Raise_Error
  663.      * @param string package name
  664.      * @param string|array callback
  665.      * @static
  666.      */
  667.     function setErrorMsgGenerator($package, $errorMsgGenerator)
  668.     {
  669.         if ($errorMsgGenerator) {
  670.             $package = strtolower($package);
  671.             Error_Raise::disableErrorCallbacks();
  672.             $e = Error_Util::_validCallback($errorMsgGenerator);
  673.             Error_Raise::reenableErrorCallbacks();
  674.             if (PEAR::isError($e)) {
  675.                 return $e->rePackageError('Error_Raise', 'error',
  676.                     ERROR_RAISE_ERROR_INVALID_ERRMSGGEN,
  677.                     array('package' => $package));
  678.             }
  679.             $GLOBALS['_ERROR_RAISE_MSGS'][$package] = $errorMsgGenerator;
  680.             return true;
  681.         }
  682.     }
  683.     
  684.     /**
  685.      * Set the function/method used to retrieve context information
  686.      * for an error, like the file and line number that generated an error.
  687.      *
  688.      * In most cases, the file or line number is the file/line returned from
  689.      * the debug_backtrace() called at the error's creation.  In some cases,
  690.      * the error/warning/notice occurs when processing another file, and this
  691.      * function can be used to set the callback that should be used to
  692.      * retrieve this information.
  693.      *
  694.      * A function passed to setContextGrabber() must return an associative
  695.      * array of values.  These values will be assigned to properties of a new
  696.      * error object created by {@link raise()}.  In this way, the properties can
  697.      * be used by {@link Error_Raise_Error::getErrorPrefix()} to generate
  698.      * context-specific information for each error.
  699.      *
  700.      * An example of a custom context grabber:
  701.      *
  702.      * <code>
  703.      * class doesDB {
  704.      *     /**
  705.      *      * We ignore the backtrace and instead use DB-specific information
  706.      *      * @param array debug_backtrace() output
  707.      *      * @param integer backtrace frame to use
  708.      *      {@*}
  709.      *     function grabContext($trace, $frame)
  710.      *     {
  711.      *         $return = array(
  712.      *            '_db' => $this->_databaseName,
  713.      *            '_table' => $this->_tableName,
  714.      *            '_queryPos' => $this->_queryPos,);
  715.      *     }
  716.      * }
  717.      * </code>
  718.      *
  719.      * Then, you can use this context information in a custom implementation
  720.      * of {@link Error_Raise_Error::getErrorPrefix()}
  721.      *
  722.      * <code>
  723.      * $db = &new doesDB;
  724.      * Error_Raise::setContextGrabber('myDB', array(&$db, 'grabContext'));
  725.      * ...
  726.      * class myDB_Error extends Error_Raise_Error {
  727.      *     function getErrorPrefix($state = ERROR_RAISE_TEXT)
  728.      *     {
  729.      *         $prefix = $this->getPackage() . ' ' . $this->getErrorType();
  730.      *         if (isset($this->_db)) {
  731.      *             $prefix .= ' in database "' . $this->_db . '"';
  732.      *         }
  733.      *         if (isset($this->_table)) {
  734.      *             $prefix .= ', ' . $this->_table;
  735.      *         }
  736.      *         if (isset($this->_queryPos)) {
  737.      *             $prefix .= ' query position ' . $this->_queryPos;
  738.      *         }
  739.      *         $prefix .= ' : ';
  740.      *     }
  741.      * }
  742.      * </code>
  743.      * @param string package name
  744.      * @param string|array
  745.      * @static
  746.      */
  747.     function setContextGrabber($package, $fileline)
  748.     {
  749.         $package = strtolower($package);
  750.         $GLOBALS['_ERROR_RAISE_CONTEXTGRABBER'][$package] = $fileline;
  751.         return true;
  752.     }
  753.     
  754.     /**
  755.      * Get an Error_Raise error message from a code
  756.      *
  757.      * This is the error message generator for the Error_Raise package, and
  758.      * should not be used by other packages.  It can be used as an example
  759.      * of one way to generate an error message
  760.      * @access private
  761.      * @return string error message from error code
  762.      * @param integer
  763.      * @param array
  764.      * @static
  765.      */
  766.     function _getErrorMessage($code, $args = array(), $state = ERROR_RAISE_TEXT)
  767.     {
  768.         if (!is_array($args)) {
  769.             return 'Error: $args passed to Error_Raise::_getErrorMessage is '.
  770.                 'not an array but a '.gettype($args);
  771.         }
  772.         $messages =
  773.         array(
  774.             ERROR_RAISE_ERROR_CLASS_DOESNT_EXIST =>
  775.                 'class "%cl%" does not exist',
  776.             ERROR_RAISE_ERROR_CODENOMSG =>
  777.                 'package "%package%" has no registered error message '
  778.                     . 'generator',
  779.             ERROR_RAISE_ERROR_ALREADY_INITIALIZED =>
  780.                 'package "%package%" has already been initialized',
  781.             ERROR_RAISE_ERROR_INVALID_INPUT =>
  782.                 'invalid input, parameter #%paramnum% '
  783.                     . '"%var%" was expecting '
  784.                     . '"%expected%", instead got "%was%"',
  785.             ERROR_RAISE_ERROR_INVALID_ERROR_CLASS =>
  786.                 'error class "%class%" in package '
  787.                     . '"%package%," error type '
  788.                     . '"%type%" does not descend from '
  789.                     . 'Error_Raise_Error.  Use '
  790.                     . 'PEAR::raiseError() for normal PEAR_Error classes',
  791.             ERROR_RAISE_ERROR_INVALID_ERRMSGGEN =>
  792.                 'Invalid callback passed to setErrorMsgGenerator() for package'
  793.                     . ' %package%',
  794.             ERROR_RAISE_ERROR_INVALID_CONTEXT_GRABBER =>
  795.                 'An invalid callback was passed as a context grabber for '
  796.                     . 'package %package%',
  797.             ERROR_RAISE_ERROR_INVALID_CONTEXTGRABBER_RETURN =>
  798.                 'The context grabber for package %package% did not return an '
  799.                     . 'array, but instead returned a %type%',
  800.              );
  801.         if (is_int($code) && isset($messages[$code])) {
  802.             $msg = $messages[$code];
  803.             return Error_Raise::sprintfErrorMessageWithState($msg,
  804.                 $args, $state);
  805.         } else {
  806.             return 'Error: code ' . $code . ' not found';
  807.         }
  808.     }
  809.     
  810.     /**
  811.      * Simple utility function for replacing variables with values in an error
  812.      * message template
  813.      *
  814.      * This simple str_replace-based function can be used to have an
  815.      * order-independent sprintf, so error messages can be passed in
  816.      * with different grammar ordering, or other possibilities without
  817.      * changing the source code.
  818.      *
  819.      * In addition, if the argument is an object and has a toString() method,
  820.      * it will be called in order to transform the object into viewable text.
  821.      * If it is an array, the values will be joined together by commas
  822.      *
  823.      * Variables should simply be surrounded by % as in %varname%
  824.      * @param string error message template
  825.      * @param array associative array of template var -> message text
  826.      * @see sprintfErrorMessageWithState
  827.      * @static
  828.      */
  829.     function sprintfErrorMessage($msg, $args)
  830.     {
  831.         if (is_array($args)) {
  832.             foreach($args as $name => $value) {
  833.                 $val = $value;
  834.                 if (is_object($value) && method_exists($value, 'tostring')) {
  835.                     $val = $value->toString();
  836.                 }
  837.                 if (is_array($value)) {
  838.                     $i = 0;
  839.                     $val = '';
  840.                     foreach($value as $item) {
  841.                         if ($i++ > 0) {
  842.                             $val .= ', ';
  843.                         }
  844.                         $val .= $item;
  845.                     }
  846.                 }
  847.                 $msg = str_replace("%$name%", $val, $msg);
  848.             }
  849.         }
  850.         return $msg;
  851.     }
  852.     
  853.     /**
  854.      * Simple utility function for replacing variables with values in an error
  855.      * message template, with special formatting for state.
  856.      *
  857.      * This simple str_replace-based function can be used to have an
  858.      * order-independent sprintf, so error messages can be passed in
  859.      * with different grammar ordering, or other possibilities without
  860.      * changing the source code.
  861.      *
  862.      * In addition, if the argument is an object and has a toString() method,
  863.      * it will be called in order to transform the object into viewable text.
  864.      * If it is an array, the values will be joined together by commas
  865.      *
  866.      * Variables should simply be surrounded by % as in %varname%
  867.      * @param string error message template
  868.      * @param array associative array of template var -> message text
  869.      * @param ERROR_RAISE_TEXT|ERROR_RAISE_ANSI|ERROR_RAISE_HTML
  870.      * @see sprintfErrorMessage
  871.      * @static
  872.      */
  873.     function sprintfErrorMessageWithState($msg, $args, $state)
  874.     {
  875.         if (is_array($args)) {
  876.             foreach($args as $name => $value) {
  877.                 $val = $value;
  878.                 if (is_object($value) && method_exists($value, 'tostring')) {
  879.                     $val = $value->toString();
  880.                 }
  881.                 if (is_array($value)) {
  882.                     $i = 0;
  883.                     $val = '';
  884.                     foreach($value as $item) {
  885.                         if ($i++ > 0) {
  886.                             $val .= ', ';
  887.                         }
  888.                         $val .= $item;
  889.                     }
  890.                 }
  891.                 if ($state == ERROR_RAISE_ANSI) {
  892.                     $msg = str_replace("%$name%",
  893.                         '%r%U%%' . $val . '%%U%r', $msg);
  894.                 } elseif ($state == ERROR_RAISE_HTML) {
  895.                     $msg = str_replace("%$name%", 
  896.                         '<strong>' . $val . '</strong>', $msg);
  897.                 } else {
  898.                     $msg = str_replace("%$name%", $val, $msg);
  899.                 }
  900.             }
  901.         }
  902.         if ($state == ERROR_RAISE_HTML) {
  903.             return nl2br($msg);
  904.         }
  905.         return $msg;
  906.     }
  907. }
  908.  
  909. if (!function_exists('is_a')) {
  910. /**
  911.  * @ignore
  912.  */
  913. function is_a($obj, $classname)
  914. {
  915.     return (get_class($obj) == strtolower($classname)) ||
  916.         is_subclass_of($obj, $classname);
  917. }
  918. }
  919. ?>
  920.