upgrade to PEAR_ErrorStack for PEAR2?

From: 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

« previous php.pear.dev (#47939) next »