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.p
hp.net/wsvn/PEARSVN/Pyrus/trunk/src/MultiErrors.php?op=file&
amp;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
--
PEAR Development Mailing List (http://pear.php.net/)
To unsubscribe, visit: http://www.php.net/unsub
.php
|