upgrade to PEAR_ErrorStack for PEAR2?
| From: | Gregory Beaver | Date: | Fri, 07 Sep 2007 04:48:29 +0000 |
| Subject: | upgrade to PEAR_ErrorStack for PEAR2? | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-47939@lists.php.net to get a copy of this message | ||
Hi all,
As I was working on Pyrus, I ran into a situation where I needed a way
to aggregate multiple errors into a single place where it would be then
easy to decide later whether the errors are serious enough to warrant
throwing an exception, or could simply be logged as warnings/notices to
the user. This was (of course) package.xml validation.
One of the scenarios PEAR_ErrorStack was designed for was aggregating
multiple errors of differing severity and making it easy to work with them.
For PEAR2_Pyrus, I've taken a different (and much simpler) approach to
solving the problem, code is here:
http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/trunk/src/MultiErrors.php?op=file&rev=0&sc=1
Basically, the entire concept of a global/local combined error handling
system is ditched, along with the idea of a stack. Instead, three
PHP5-specific interfaces are used to make the PEAR2_Pyrus_MultiErrors
class much simpler to use than PEAR_ErrorStack.
Instead of taking lots of complicated parameters to hold errors in
arrays, PEAR2_Pyrus_MultiErrors simply accepts exception classes. This
leverages PHP's built-in ability to encapsulate error information,
context on where the error occurred, and other fun stuff within a single
object. A MultiErrors object uses ArrayAccess to add errors to its
list, and can categorize them based on three severities. I re-used the
built-in E_ERROR, E_WARNING, and E_NOTICE constants to categorize the
errors, as this should cover all possible error types. Anything else
should probably be handled by a logging system and not this class.
Basically, one adds errors via:
<?php
$multi = new PEAR2_Pyrus_MultiErrors;
$multi[E_WARNING] = new PEAR2_MyPackage_Exception('whatever');
$multi[E_WARNING] = new PEAR2_MyPackage_Exception('another thing');
$multi[E_NOTICE] = new PEAR2_MyPackage_Exception('some small thing');
$multi[E_ERROR] = new PEAR2_MyPackage_Exception('big deal');
?>
When the end of a logic block that generates lots of potential errors of
different severity is reached, we can access each error in turn and log
them using foreach():
<?php
foreach ($multi as $error) {
}
?>
or we can loop over specific levels:
<?php
foreach ($multi[E_WARNING] as $warnings) {
}
?>
or we can use count() to test for any errors at all:
<?php
if (count($multi)) {
throw new PEAR2_Exception('stuff broke', $multi);
}
?>
or more usefully, we can test for a specific level:
<?php
if (count($multi[E_ERROR])) {
throw new PEAR2_Exception('stuff broke', $multi);
}
?>
This kind of multiple levels of errors can allow simulation of
error_reporting() using exceptions, but in a more controlled way. For
instance, while debugging, one might want to always throw an exception
if any error occurs:
<?php
if ($debug && count($multi)) throw new PEAR2_Exception(...);
?>
or one might want to log all warnings/notices no matter what, but throw
an exception if there are errors:
<?php
if (count($multi[E_NOTICE])) {
foreach ($multi[E_NOTICE] as $notice) {
$log->log('Notice: ' . $notice->getMesasge());
}
}
if (count($multi[E_WARNING])) {
foreach ($multi[E_WARNING] as $warning) {
$log->log('WARNING: ' . $warning->getMessage());
}
}
if (count($multi[E_ERROR])) {
throw new PEAR2_Exception('bad junk happened', $multi);
}
?>
These code samples all assume that PEAR2_Exception would accept a
MultiErrors-based interface as a $cause that would look something like:
<?php
interface PEAR2_Exception_ICause
{
/**
* Retrieve an array of exceptions that caused this Exception
*/
function getArray();
}
?>
My question is whether this is a useful enough general-purpose class to
consider promoting from PEAR2_Pyrus_MultiErrors to PEAR2_MultiErrors?
Greg