Re: Common way of error handling?
| From: | Ulf Wendel | Date: | Sat, 13 May 2000 12:59:22 +0000 |
| Subject: | Re: Common way of error handling? | ||
| References: | 1 2 | Groups: | php.pear |
| Request: | Send a blank email to php-pear+get-101@lists.php.net to get a copy of this message | ||
Stig Bakken wrote:
>
> Ulf Wendel wrote:
> >
> > Hi!
> >
> > Is there a common way of error handling in PEAR modules?
>
> There isn't. Personally, I like Java's exceptions in that you throw
> objects, and that you can subclass exception classes. DB has a somewhat
> abstracted error concept (where the definition of "error" currently is
> "negative integer"). It would make sense to steal some from Java and
> extend this to make the error concept "an object of this class (or a
> subclass)" and make it general at the same time.
I also like the way to adopt the java way (again). I've played a lot
with the problem of error handling. I started somewhat similiar the way
you have choosed in DB just not that elegant. This way has some
problems:
- return values suddenly change their type
- you have long lists (array or defines) with error messages
Later on I decided to have one class "error" that handles errors. I
passed the error message and the error number to it an let it do the
work. It was up to "error" to supress the message, print it or even halt
the script.
With PHP we can't realize the java way, because we don't have try-catch
and throw. But we could overtake some ideas from the class hierarchie,
mix the exception and the execption handling within one class hierarchie
to get some of java features. (Puh - he seens to be drunk, what does he
mean?)
Let's look at the key features we need:
1. It must be easy to create an exception within a module.
2. All PEAR modules should have a predefined default behaviour.
3. Each PEAR module must be able to override the predefined behaviour.
4. Each PEAR module must be able to control the reaction on an exception
(show, halt), override its own default behaviour.
5. The user should be able to override the default behaviour of a
module.
Extended "features":
6. There're predefined exceptions.
7. There're different "levels of exceptions": error, warning, notice).
8. There're diffent "kinds of exception":
- Runtime (caused by the module itself)
- User (caused by the programmer when using the module)
- IOException
+++ creating an exception +++
Creating an exception must be as easy as possible and the programmer
must be able to decide wether to rely on the default exception handling
or to override it.
+ Syntax
new pear_NameOfException ( [string $message, int $errno , string
$filename, int $linenum, bool $auto_handle ]);
+ Examples
<?php new pear_notice("my notice"); ?>
Create a simple note. It's up the the default pear_notice class how to
handle it. I suggest don't show, don't halt.
<?php new pear_warning("my warning", -1000, __FILE__, __LINE__); ?>
Create a warning, provide the exception handler with an error code, the
current filename and the current line number. It's up to the default
pear_warning class how to handle it. I suggest show, but don't halt.
Show always means "show all possible informations, no matter if $errno,
$file or $linenum are defined".
<?php $err=new pear_error("my_error", -1, __FILE__, __LINE__, false); ?>
Create an Error, provide the exception handler with an error code, the
default filename and the current line number. The default exception
handling is switched off.
Now you can decide to call:
- $err->handle(), default handling
- $err->show(), show the error but don't halt
- $err->halt(), show the error and halt
As your PEAR modules controles the bahaviour, you can exit your function
returning a value of the promised type or halt if necessary.
+++ default behaviour of PEAR modules +++
We can gain default behaviour if we use polymorhism.
Up to this point we haven't thought about the class hierarchie not even
on what classes we need. We have to start with it now to understand my
thoughts.
We have two basis tasks:
- defining exceptions
- handling defined exception
Translating this to the oo world gives something like this (kind of UML
notation):
---------------------
| exception handler |
| |
| show(), halt() |
---------------------
^ 1
|
| 1
---------------------
| exception |
| |
| create exception |
---------------------
The default PEAR behaviour resides on level three:
---------------------
| PEAR |
| exception handler |
---------------------
^ 1
|
| 1
---------------------
| exception handler |
| |
| handle() |
---------------------
^ 1
|
| 1
---------------------
| exception |
| |
| create exception |
---------------------
On level four I placed predefined PEAR exceptions such as PEAR_Warning,
PEAR_Error, PEAR_Notice:
---------------------
| PEAR_Warning |
| |
---------------------
^ 1
|
| 1
---------------------
| PEAR |
| exception handler |
| |
| handler_warning() |
| handler_error() |
| handler_notice() |
---------------------
[...]
On level four a class is usually pretty small, there's only a
constructor (see creating an exception). The constructor passes most of
its arguments to exception::exception() and calls
pear_exception_handler::handle() if requested (default). That's all.
Level four is a keypoint. I can't make up my mind how it should look
like. Does the class tree branch on the "level of an exception" (notice,
warning, error) and stop as shown or do we follow the Java way?
Java has no need to mix the event handling and event creation together.
They have try-catch and throw, we do not. In Java there is no need to
define "levels of exceptions". It's up to who ever catches the exception
to "rate" it, to give it a certain "level" (notice, warning, error).
Java branches the tree at this point on the "kind of an exception"
(Runtime, IOException). Translated to the PHP/PEAR world we would get
something like this if we like the idea of "levels":
exception::exception_handler::pear_exception_handler::pear_runtime::pear_runtimeerror::pear_wrongparamcount
exception::exception_handler::pear_exception_handler::pear_ioexception::pear_ioerror::pear_direrror
... somewhat to complicated.
The concept of "levels" (notice, warning, error) seems to be a must in
the PHP world. I suggest rating it that high the class modell stops on
level four. Introducting a deeper class modell would mean overdoing it.
exception::exception_handler::pear_exceptiion_handler::pear_warning::pear_io
exception::exception_handler::pear_exceptiion_handler::pear_warning::pear_runtime
exception::exception_handler::pear_exceptiion_handler::pear_error::pear_io
Instead of this preferr a "faulty" compromise: default exceptions stay
on level four:
pear_notice, notes that fit nowhere else
pear_warning, warnings that fit nowhere else
prear_error, errors that fit nowhere else
pear_ioexception, an error while dealing with io
pear_runtime, a warning that is cause due to wrong use of functions
+++ default behavoir of a module +++
Each PEAR module can override the default PEAR exceptions classes and
even more provide new exceptions, although I don't thing that this is
really necessary for most of the smaller modules.
+++ the user should be able to control the exception handling +++
This is necessary e.g. for customizing the handleException() methods
that prints the exception, or instance vars such as show_error or
halt_on_error. The user could even want use mail() to get informed by
e-mail whenever an error occurs.
Customization can be done by modifing the exception classes of the
module. Experienced users might even modify the pear exception classes.
+++ API +++
He're an API demo of the sketched modell:
<?php
class my_pear_module {
function createNotice() {
new pear_notice("my_notice");
}
function createWarning() {
new pear_warning("my_warning", 1000, __FILE__, __LINE__);
}
/**
* @return bool $ok
*/
function createError() {
if (true) {
$err = new pear_error("my_error", 1, __FILE__, __LINE___, false);
$err->show();
return false;
}
return true;
}
}
my_pear_module::createNotice();
my_pear_module::createWarning();
my_pear_module::createError();
?>
The class hierachie is pretty simple (as shown above). It takes less
than 200 loc in PHP, it's flexible and can be configured widely. It does
not come with major restrictions. How about it?
Ulf