List Info

Thread: upgrade to PEAR_ErrorStack for PEAR2?




upgrade to PEAR_ErrorStack for PEAR2?
user name
2007-09-06 23:48:29
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


Re: upgrade to PEAR_ErrorStack for PEAR2?
user name
2007-09-07 08:18:24
On 9/6/07, Gregory Beaver <gregchiaraquartet.net>
wrote:
>
>
> My question is whether this is a useful enough
general-purpose class to
> consider promoting from PEAR2_Pyrus_MultiErrors to
PEAR2_MultiErrors?
>

+1

All it should take is two more packages liking this concept
and wanting to
use it, and you'd be looking at refactoring it up the stack
at that point...
so I'd vote to do it now.  I like the way you use the E_*
which should be an
already-familiar grouping mechanism for most PHPers to see
and follow.

-- 
CRB

Let me introduce you to my very own DMCA-protected
encryption key:
BC 1B 64 4A 8D DE 49 E8 C3 7D CC EE 1A AD EE F5
(compliments of Freedom-to-Tinker http://www.f
reedom-to-tinker.com/?p=1155)
Re: upgrade to PEAR_ErrorStack for PEAR2?
user name
2007-09-20 00:08:49
Travis Swicegood wrote:
> I like it with one exception:
> 
> On Sep 6, 2007, at 11:48 PM, Gregory Beaver wrote:
> 
>> <?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');
>> ?>
> 
> No no no... 
> 
> $multi[E_WARNING][] = new Exception();
> $multi[E_WARNING][] = new Exception();
> 
> Doing the magic there is just confusing with no gain. 
You could change
> the API around a bit to determine which errors it would
hold on to too
> which would help free up memory if a bunch of notices
got thrown:
> 
> $multi = new PEAR2_MultiErrors();
> $errorsOnly = new PEAR2_MultiErrors(E_ERROR);
> 
> Basically, make the constructor take a similar
parameter to
> error_reporting() and when nothing is given assume it
wants to hold onto
> everything.

I haven't added this bit yet, but I have refactored it to
work as:

$multi->E_WARNING[] = new Exception();

The filter is looser, so you can make up your own E_
levels:

$multi->E_WHATEVER[] = new Exception();

In terms of saving memory, this may happen, but is not
likely to be a
big issue, as multierrors is most likely to be used inside
a
method/class and freed upon exit, but it will be added if I
can do it well.

Greg

-- 
PEAR Development Mailing List (http://pear.php.net/)
To unsubscribe, visit: http://www.php.net/unsub
.php


[1-3]

about | contact  Other archives ( Real Estate discussion Medical topics )