Error handling and Error raising in PEAR
| From: | Greg Beaver | Date: | Tue, 12 Aug 2003 19:39:55 +0000 |
| Subject: | Error handling and Error raising in PEAR | ||
| References: | 1 2 3 4 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-19579@lists.php.net to get a copy of this message | ||
FYI,
I'm working on an extensive change to the API for error handling. It's backwards compatible to existing PEAR_Error, but adds much-needed features and constraints to existing error raising and error handling.
Note that the examples below show good error practice, not necessarily what one finds in most of PEAR :).
Here's a preview of the differences:
BEFORE:
<?php
define('MYPACKAGE_ERROR_CODE', 1);
class MyPackage_Error extends PEAR_Error {
function getMessage()
{
switch ($this->code) {
case MYPACKAGE_ERROR_CODE :
$msg = sprintf('This %s did not work', $this->userinfo);
break;
}
return $this->getErrorPrefix() . $msg;
}
function getErrorPrefix()
{
return 'MyPackage ' . str_replace('mypackage_', '',
get_class($this)) . ' ';
}
}
class MyPackage_Warning extends MyPackage_Error {}
if (baderrorcondition) {
return PEAR::raiseError('', MYPACKAGE_ERROR_CODE, null, 'mypackage operation', 'mypackage_warning');
}
?>
handling code:
<?php
if (PEAR::isError($e)) {
$classname = $e->getType();
if (strpos($classname, 'mypackage_') == 0) {
switch(str_replace('mypackage_', $classname)) {
case 'error' :
// handle mypackage errors
break;
case 'warning' :
// handle mypackage warnings
break;
}
}
?>
Note that to get some basic functionality (figuring out the package of the error, adding in error-specific data, having error levels like warning/notice/error) requires tons of barely-readable code. Here's how the new API looks:
AFTER:
<?php
define('MYPACKAGE_ERROR_CODE', 1);
class MyPackage {
function getErrorMessage($code, $args, $state = ERROR_RAISE_TEXT)
{
switch ($code) {
case MYPACKAGE_ERROR_CODE :
$msg = 'This %operation% did not work';
break;
}
return Error_Raise::sprintfErrorMessageWithState($msg, $args, $state);
}
Error_Raise::initialize('MyPackage', array('MyPackage', 'getErrorMessage'));
if (baderrorcondition) {
return MyPackage_Raise::warning(MYPACKAGE_ERROR_CODE, array('operation' => 'mypackage operation'));
}
?>
handling code:
<?php
if (PEAR::isError($e)) {
if ($e->getPackageName() == 'mypackage') {
switch($e->getErrorType()) {
case 'error' :
// handle mypackage errors
break;
case 'warning' :
// handle mypackage warnings
break;
}
}
}
?>
Basically, the biggest differences are:
- error messages are generated at runtime, allowing customization of display (error messages could match the style of a website, or be customized for the particular user) and preservation of semantic information
- error classes are defined automatically if they don't already exist
- errors are divided into packages easily, so there is no need for a standard on which error numbers are reserved for what package, and codes can always be referred to by constant name only
- handling errors is MUCH simpler.
I'm in the process of unit-testing the raiser and handler. All of the error-specific features could easily be added to PEAR_Error without breaking BC at all, if people don't like the idea of a competing error standard.
When I have fully unit-tested code, I will post a link to docs and installation and .phps, this is just a heads up
Regards,
Greg
Alexander Merz wrote:
Christian Wenz wrote:Hm, i could bet there where more notes early... PEAR_Error was one of the first parts of PEAR for providing the mechanismen everywhere. So there was never a question how to realize this mechanismen. ("normative Kraft des Faktischen")[...] you are using code that [...] provides the same error reportingmechanism everywhere