cvs: pear-core /PEAR ErrorStack5.php Warning.php
| From: | Greg Beaver | Date: | Sat, 04 Sep 2004 03:45:30 +0000 |
| Subject: | cvs: pear-core /PEAR ErrorStack5.php Warning.php | ||
| Groups: | php.pear.cvs php.pear.core | ||
| Request: | Send a blank email to pear-cvs+get-23613@lists.php.net to get a copy of this message | ||
cellog Fri Sep 3 23:45:30 2004 EDT
Added files:
/pear-core/PEAR Warning.php
Modified files:
/pear-core/PEAR ErrorStack5.php
Log:
EXPERIMENTAL PEAR_Warning which can interoperate with PEAR_ErrorStack in PHP5 or work standalone
(preferred method)
http://cvs.php.net/diff.php/pear-core/PEAR/ErrorStack5.php?r1=1.2&r2=1.3&ty=u Index: pear-core/PEAR/ErrorStack5.php diff -u pear-core/PEAR/ErrorStack5.php:1.2 pear-core/PEAR/ErrorStack5.php:1.3 --- pear-core/PEAR/ErrorStack5.php:1.2 Wed Sep 1 22:57:56 2004 +++ pear-core/PEAR/ErrorStack5.php Fri Sep 3 23:45:30 2004 @@ -17,7 +17,7 @@ // | | // +----------------------------------------------------------------------+ // -// $Id: ErrorStack5.php,v 1.2 2004/09/02 02:57:56 cellog Exp $ +// $Id: ErrorStack5.php,v 1.3 2004/09/04 03:45:30 cellog Exp $ /** * Error Stack Implementation - E_STRICT compliant @@ -133,6 +133,15 @@ static protected $globallogger = false; /** + * PEAR_Warning callback + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + */ + static protected $pearwarningcallback = false; + + /** * Global Overriding Callback * * This callback will override any error callbacks that specific loggers have set. @@ -345,7 +354,16 @@ $package = $package ? $package : '*'; self::$globalcallback[$package] = $callback; } - + + /** + * Do not use + * @access private + */ + static public function setPEARWarningCallback($callback) + { + self::$pearwarningcallback = $callback; + } + /** * Set an error code => error message mapping callback * @@ -569,6 +587,9 @@ } } if ($push) { + if (is_callable(self::$pearwarningcallback)) { + call_user_func(self::$pearwarningcallback, $err); + } array_unshift($this->_errors, $err); $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; } http://cvs.php.net/co.php/pear-core/PEAR/Warning.php?r=1.1&p=1 Index: pear-core/PEAR/Warning.php +++ pear-core/PEAR/Warning.php <?php // +----------------------------------------------------------------------+ // | PEAR_Exception | // +----------------------------------------------------------------------+ // | Copyright (c) 2004 The PEAR Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 3.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/3_0.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Greg Beaver <cellog@php.net> | // +----------------------------------------------------------------------+ // // $Id: Warning.php,v 1.1 2004/09/04 03:45:30 cellog Exp $ require_once 'PEAR/Exception.php'; /** * Exception class for internal PEAR_Warning exceptions * @package PEAR */ class PEAR_WarningException extends PEAR_Exception {} interface PEAR_WarningInterface { /** * Get the severity of this warning ('warning', 'notice') * @return string */ public function getLevel(); } /** * Warning mechanism for PEAR PHP5-only packages. * * For users: * * Unlike PEAR_ErrorStack, PEAR_Warning is designed to be used on a transactional basis. * * <code> * <?php * require_once 'PEAR/Warning.php'; * require_once 'PEAR/Exception.php'; * class Mypackage_Exception extends PEAR_Exception {} * PEAR_Warning::begin(); * $c = new Somepackage; * $c->doSomethingComplex(); * if (PEAR_Warning::hasWarnings()) { * $warnings = PEAR_Warning::end(); * throw new Mypackage_Exception('unclean doSomethingComplex', $warnings); * } else { * $c->doSomethingElse(); * } * ?> * </code> * * Only warnings that occur between ::begin() and ::end() will be processed. Remember, * a warning is a non-fatal error, exceptions will be used for unrecoverable errors in * all PEAR packages, and you should follow this model to be safe! * * For developers: * * This class can be used globally or locally. For global use, a * series of static methods have been provided. The class is designed * for lazy loading, and so the following code will work, and increase * efficiency on production servers: * * <code> * <?php * if (class_exists('PEAR_Warning')) { * PEAR_Warning::add(1, 'mypackage', 'possible mis-spelling of something'); * } * ?> * </code> * * This means that PEAR_Warning can literally be used without the need for * require_once 'PEAR/Warning.php';! * * You can also pass in an exception class as a warning * * <code> * <?php * class MyPackage_Warning extends PEAR_Exception {} * PEAR_Warning::add(new MyPackage_Warning('some info')); * ?> * </code> * * An interface is provided to allow for severity differentiation * * <code> * <?php * class MyPackage_Warning extends PEAR_Exception implements PEAR_WarningInterface * { * private $_level = 'warning'; * function __construct($message, $level = 'warning', $p1 = null, $p2 = null) * { * $this->_level = $level; * parent::__construct($message, $p1, $p2); * } * * public function getLevel() * { * return $this->_level; * } * } * PEAR_Warning::add(new MyPackage_Warning('some info', 'notice')); * ?> * </code> * * This can be used with {@link setErrorHandling()} to ignore warnings of different severities * for complex error situations. * * For local situations like an internal warning system for a parser that may become the cause * of a single PEAR_Exception, PEAR_Warning can also be instantiated and used without any connection * to the global warning stack. * @package PEAR */ class PEAR_Warning { /** * properties used for global warning stacks */ protected static $_hasWarnings = false; protected static $warnings = array(); protected static $go = false; protected static $levels = array('warning', 'notice'); private static $_observers = array(); private static $_uniqueid = 0; /** * properties used for instantiation of private warning stack */ private $_warnings = array(); private $_go = false; private $_context; /** * Begin tracking all global warnings */ static public function begin() { if (class_exists('PEAR_ErrorStack')) { PEAR_ErrorStack::setPEARWarningCallback(array('PEAR_Warning', '_catch')); } self::$go = true; self::$_hasWarnings = false; } /** * @return bool */ static public function hasWarnings() { return self::$_hasWarnings; } /** * Stop tracking global warnings * @return array an array of all warnings in array and PEAR_Exception format * suitable for use as a PEAR_Exception cause */ static public function end() { if (class_exists('PEAR_ErrorStack')) { PEAR_ErrorStack::setPEARWarningCallback(false); } self::$go = false; self::$_hasWarnings = false; $a = self::$warnings; self::$warnings = array(); return $a; } /** * @param mixed A valid callback that accepts either a * PEAR_Exception or PEAR_ErrorStack-style array * @param string The name of the observer. Use this if you want * to remove it later with removeObserver(). * {@link getUniqueId()} can be used to generate a label */ public static function addObserver($callback, $label = 'default') { self::$_observers[$label] = $callback; } /** * @param mixed observer ID */ public static function removeObserver($label = 'default') { unset(self::$_observers[$label]); } /** * @return int unique identifier for an observer */ public static function getUniqueId() { return self::$_uniqueid++; } /** * Set the warning levels that should be captured by the warning mechanism * * WARNING: no error checking or spell checking. * @param array */ public static function setErrorHandling($levels) { self::$_levels = $levels; } /** * Add a warning to the global warning stack. * * Note: if you want file/line context, use an exception object * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an * error code or some other error class differentiation technique * @param string Package is required if $codeOrException is not a PEAR_Exception object * @param string Error message, use %param% to do automatic parameter replacement from $params * @param array Error parameters * @param string Error level, use the English name * @throws PEAR_WarningException if $codeOrException is not a PEAR_Exception and $package is not set */ static public function add($codeOrException, $package = '', $msg = '', $params = array(), $level = 'warning') { if ($codeOrException instanceof PEAR_Exception) { if ($codeOrException instanceof PEAR_WarningInterface) { if (in_array($codeOrException->getLevel(), self::$levels)) { self::_signal($codeOrException); } } else { self::_signal($codeOrException); } } else { if (empty($package)) { throw new PEAR_WarningException('Package must be set for a non-exception warning'); } if (in_array($level, self::$levels)) { $warning = self::_formatWarning($codeOrException, $package, $level, $msg, $params); self::_signal($warning); } } self::$_hasWarnings = true; } /** * @param string the package name, or other context information that can be used * to differentiate this warning from warnings thrown by other packages * @throws PEAR_WarningException if $context is not a string */ public function __construct($context) { if (!is_string($context)) { throw new PEAR_WarningException('$context constructor argument must be a string'); } $this->_context = $context; } /** * Local stack function for adding a warning - note that package is not needed, as it is * defined in the constructor. * * Note: if you want file/line context, use an exception object * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an * error code or some other error class differentiation technique * @param string Error message, use %param% to do automatic parameter replacement from $params * @param array Error parameters * @param string Error level, use the English name */ public function localAdd($code, $msg = '', $params = array(), $level = 'warning') { if ($codeOrException instanceof PEAR_Exception) { $this->_warnings[] = $codeOrException; } else { $warning = self::_formatWarning($codeOrException, $this->_context, $level, $msg); $this->_warnings[] = $warning; } } /** * Begin a local warning stack session */ public function localBegin() { $this->_warnings = array(); $this->_go = true; } /** * End a local warning stack session * @return array */ public function localEnd() { $a = $this->_warnings; $this->_warnings = array(); $this->_go = false; return $a; } /** * Do not use this function directly - it should only be used by PEAR_ErrorStack * @access private */ static public function _catch($err) { self::_signal($err); } private static function _signal($warning) { foreach (self::$_observers as $func) { if (is_callable($func)) { call_user_func($func, $this); continue; } settype($func, 'array'); switch ($func[0]) { case PEAR_EXCEPTION_PRINT : $f = (isset($func[1])) ? $func[1] : '%s'; printf($f, $this->getMessage()); break; case PEAR_EXCEPTION_TRIGGER : $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; trigger_error($this->getMessage(), $f); break; case PEAR_EXCEPTION_DIE : $f = (isset($func[1])) ? $func[1] : '%s'; die(printf($f, $this->getMessage())); break; default: trigger_error('invalid observer type', E_USER_WARNING); } } } static private function _formatWarning($code, $package, $level, $msg, $params, $backtrace) { return array('package' => $package, 'code' => $code, 'level' => $level, 'message' => self::_formatMessage($msg, $params), 'params' => $params); } static private function _formatMessage($msg, $params) { if (count($params)) { foreach ($params as $name => $val) { if (strpos($msg, '%' . $name . '%') !== false) { if (is_array($val)) { // don't pass in an array that you expect to display unless it is 1-dimensional! $val = implode(', ', $val); } if (is_object($val)) { if (method_exists($val, '__toString')) { $val = $val->__toString(); } else { $val = 'Object'; } } $msg = str_replace('%' . $name . '%', $val, $msg); } } } return $msg; } } ?>
http://cvs.php.net/diff.php/pear-core/PEAR/ErrorStack5.php?r1=1.2&r2=1.3&ty=u Index: pear-core/PEAR/ErrorStack5.php diff -u pear-core/PEAR/ErrorStack5.php:1.2 pear-core/PEAR/ErrorStack5.php:1.3 --- pear-core/PEAR/ErrorStack5.php:1.2 Wed Sep 1 22:57:56 2004 +++ pear-core/PEAR/ErrorStack5.php Fri Sep 3 23:45:30 2004 @@ -17,7 +17,7 @@ // | | // +----------------------------------------------------------------------+ // -// $Id: ErrorStack5.php,v 1.2 2004/09/02 02:57:56 cellog Exp $ +// $Id: ErrorStack5.php,v 1.3 2004/09/04 03:45:30 cellog Exp $ /** * Error Stack Implementation - E_STRICT compliant @@ -133,6 +133,15 @@ static protected $globallogger = false; /** + * PEAR_Warning callback + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + */ + static protected $pearwarningcallback = false; + + /** * Global Overriding Callback * * This callback will override any error callbacks that specific loggers have set. @@ -345,7 +354,16 @@ $package = $package ? $package : '*'; self::$globalcallback[$package] = $callback; } - + + /** + * Do not use + * @access private + */ + static public function setPEARWarningCallback($callback) + { + self::$pearwarningcallback = $callback; + } + /** * Set an error code => error message mapping callback * @@ -569,6 +587,9 @@ } } if ($push) { + if (is_callable(self::$pearwarningcallback)) { + call_user_func(self::$pearwarningcallback, $err); + } array_unshift($this->_errors, $err); $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; } http://cvs.php.net/co.php/pear-core/PEAR/Warning.php?r=1.1&p=1 Index: pear-core/PEAR/Warning.php +++ pear-core/PEAR/Warning.php <?php // +----------------------------------------------------------------------+ // | PEAR_Exception | // +----------------------------------------------------------------------+ // | Copyright (c) 2004 The PEAR Group | // +----------------------------------------------------------------------+ // | This source file is subject to version 3.0 of the PHP license, | // | that is bundled with this package in the file LICENSE, and is | // | available at through the world-wide-web at | // | http://www.php.net/license/3_0.txt. | // | If you did not receive a copy of the PHP license and are unable to | // | obtain it through the world-wide-web, please send a note to | // | license@php.net so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // | Authors: Greg Beaver <cellog@php.net> | // +----------------------------------------------------------------------+ // // $Id: Warning.php,v 1.1 2004/09/04 03:45:30 cellog Exp $ require_once 'PEAR/Exception.php'; /** * Exception class for internal PEAR_Warning exceptions * @package PEAR */ class PEAR_WarningException extends PEAR_Exception {} interface PEAR_WarningInterface { /** * Get the severity of this warning ('warning', 'notice') * @return string */ public function getLevel(); } /** * Warning mechanism for PEAR PHP5-only packages. * * For users: * * Unlike PEAR_ErrorStack, PEAR_Warning is designed to be used on a transactional basis. * * <code> * <?php * require_once 'PEAR/Warning.php'; * require_once 'PEAR/Exception.php'; * class Mypackage_Exception extends PEAR_Exception {} * PEAR_Warning::begin(); * $c = new Somepackage; * $c->doSomethingComplex(); * if (PEAR_Warning::hasWarnings()) { * $warnings = PEAR_Warning::end(); * throw new Mypackage_Exception('unclean doSomethingComplex', $warnings); * } else { * $c->doSomethingElse(); * } * ?> * </code> * * Only warnings that occur between ::begin() and ::end() will be processed. Remember, * a warning is a non-fatal error, exceptions will be used for unrecoverable errors in * all PEAR packages, and you should follow this model to be safe! * * For developers: * * This class can be used globally or locally. For global use, a * series of static methods have been provided. The class is designed * for lazy loading, and so the following code will work, and increase * efficiency on production servers: * * <code> * <?php * if (class_exists('PEAR_Warning')) { * PEAR_Warning::add(1, 'mypackage', 'possible mis-spelling of something'); * } * ?> * </code> * * This means that PEAR_Warning can literally be used without the need for * require_once 'PEAR/Warning.php';! * * You can also pass in an exception class as a warning * * <code> * <?php * class MyPackage_Warning extends PEAR_Exception {} * PEAR_Warning::add(new MyPackage_Warning('some info')); * ?> * </code> * * An interface is provided to allow for severity differentiation * * <code> * <?php * class MyPackage_Warning extends PEAR_Exception implements PEAR_WarningInterface * { * private $_level = 'warning'; * function __construct($message, $level = 'warning', $p1 = null, $p2 = null) * { * $this->_level = $level; * parent::__construct($message, $p1, $p2); * } * * public function getLevel() * { * return $this->_level; * } * } * PEAR_Warning::add(new MyPackage_Warning('some info', 'notice')); * ?> * </code> * * This can be used with {@link setErrorHandling()} to ignore warnings of different severities * for complex error situations. * * For local situations like an internal warning system for a parser that may become the cause * of a single PEAR_Exception, PEAR_Warning can also be instantiated and used without any connection * to the global warning stack. * @package PEAR */ class PEAR_Warning { /** * properties used for global warning stacks */ protected static $_hasWarnings = false; protected static $warnings = array(); protected static $go = false; protected static $levels = array('warning', 'notice'); private static $_observers = array(); private static $_uniqueid = 0; /** * properties used for instantiation of private warning stack */ private $_warnings = array(); private $_go = false; private $_context; /** * Begin tracking all global warnings */ static public function begin() { if (class_exists('PEAR_ErrorStack')) { PEAR_ErrorStack::setPEARWarningCallback(array('PEAR_Warning', '_catch')); } self::$go = true; self::$_hasWarnings = false; } /** * @return bool */ static public function hasWarnings() { return self::$_hasWarnings; } /** * Stop tracking global warnings * @return array an array of all warnings in array and PEAR_Exception format * suitable for use as a PEAR_Exception cause */ static public function end() { if (class_exists('PEAR_ErrorStack')) { PEAR_ErrorStack::setPEARWarningCallback(false); } self::$go = false; self::$_hasWarnings = false; $a = self::$warnings; self::$warnings = array(); return $a; } /** * @param mixed A valid callback that accepts either a * PEAR_Exception or PEAR_ErrorStack-style array * @param string The name of the observer. Use this if you want * to remove it later with removeObserver(). * {@link getUniqueId()} can be used to generate a label */ public static function addObserver($callback, $label = 'default') { self::$_observers[$label] = $callback; } /** * @param mixed observer ID */ public static function removeObserver($label = 'default') { unset(self::$_observers[$label]); } /** * @return int unique identifier for an observer */ public static function getUniqueId() { return self::$_uniqueid++; } /** * Set the warning levels that should be captured by the warning mechanism * * WARNING: no error checking or spell checking. * @param array */ public static function setErrorHandling($levels) { self::$_levels = $levels; } /** * Add a warning to the global warning stack. * * Note: if you want file/line context, use an exception object * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an * error code or some other error class differentiation technique * @param string Package is required if $codeOrException is not a PEAR_Exception object * @param string Error message, use %param% to do automatic parameter replacement from $params * @param array Error parameters * @param string Error level, use the English name * @throws PEAR_WarningException if $codeOrException is not a PEAR_Exception and $package is not set */ static public function add($codeOrException, $package = '', $msg = '', $params = array(), $level = 'warning') { if ($codeOrException instanceof PEAR_Exception) { if ($codeOrException instanceof PEAR_WarningInterface) { if (in_array($codeOrException->getLevel(), self::$levels)) { self::_signal($codeOrException); } } else { self::_signal($codeOrException); } } else { if (empty($package)) { throw new PEAR_WarningException('Package must be set for a non-exception warning'); } if (in_array($level, self::$levels)) { $warning = self::_formatWarning($codeOrException, $package, $level, $msg, $params); self::_signal($warning); } } self::$_hasWarnings = true; } /** * @param string the package name, or other context information that can be used * to differentiate this warning from warnings thrown by other packages * @throws PEAR_WarningException if $context is not a string */ public function __construct($context) { if (!is_string($context)) { throw new PEAR_WarningException('$context constructor argument must be a string'); } $this->_context = $context; } /** * Local stack function for adding a warning - note that package is not needed, as it is * defined in the constructor. * * Note: if you want file/line context, use an exception object * @param PEAR_Exception|string|int Either pass in an exception to use as the warning, or an * error code or some other error class differentiation technique * @param string Error message, use %param% to do automatic parameter replacement from $params * @param array Error parameters * @param string Error level, use the English name */ public function localAdd($code, $msg = '', $params = array(), $level = 'warning') { if ($codeOrException instanceof PEAR_Exception) { $this->_warnings[] = $codeOrException; } else { $warning = self::_formatWarning($codeOrException, $this->_context, $level, $msg); $this->_warnings[] = $warning; } } /** * Begin a local warning stack session */ public function localBegin() { $this->_warnings = array(); $this->_go = true; } /** * End a local warning stack session * @return array */ public function localEnd() { $a = $this->_warnings; $this->_warnings = array(); $this->_go = false; return $a; } /** * Do not use this function directly - it should only be used by PEAR_ErrorStack * @access private */ static public function _catch($err) { self::_signal($err); } private static function _signal($warning) { foreach (self::$_observers as $func) { if (is_callable($func)) { call_user_func($func, $this); continue; } settype($func, 'array'); switch ($func[0]) { case PEAR_EXCEPTION_PRINT : $f = (isset($func[1])) ? $func[1] : '%s'; printf($f, $this->getMessage()); break; case PEAR_EXCEPTION_TRIGGER : $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; trigger_error($this->getMessage(), $f); break; case PEAR_EXCEPTION_DIE : $f = (isset($func[1])) ? $func[1] : '%s'; die(printf($f, $this->getMessage())); break; default: trigger_error('invalid observer type', E_USER_WARNING); } } } static private function _formatWarning($code, $package, $level, $msg, $params, $backtrace) { return array('package' => $package, 'code' => $code, 'level' => $level, 'message' => self::_formatMessage($msg, $params), 'params' => $params); } static private function _formatMessage($msg, $params) { if (count($params)) { foreach ($params as $name => $val) { if (strpos($msg, '%' . $name . '%') !== false) { if (is_array($val)) { // don't pass in an array that you expect to display unless it is 1-dimensional! $val = implode(', ', $val); } if (is_object($val)) { if (method_exists($val, '__toString')) { $val = $val->__toString(); } else { $val = 'Object'; } } $msg = str_replace('%' . $name . '%', $val, $msg); } } } return $msg; } } ?>