Re: Common way of error handling?
| From: | Stig Bakken | Date: | Tue, 16 May 2000 10:33:21 +0000 |
| Subject: | Re: Common way of error handling? | ||
| References: | 1 2 3 4 5 | Groups: | php.pear |
| Request: | Send a blank email to php-pear+get-104@lists.php.net to get a copy of this message | ||
Ulf Wendel wrote:
>
> In the DB module Stig made the decision that a function can have several
> return types. If it's a negative integer from -1 to -999 it's an error
> occured. If it's less than -999 a warning is thrown. The user writes
> something like this:
>
> <?php
> $obj = DB::factory();
> if (!is_object($obj))
> print $db->ErrorMessage($obj);
> ?>
This is how I intended error detection:
<?php
$obj = DB::facrory();
if (DB::isError($obj))
print DB::ErrorMessage($obj);
?>
The details of "an error is a negative integer between -1 and -999" is
hidden from the user. This was done to make it easier to switch to
another error reporting mechanism (the way the error codes are checked
would have to be changed, but it's easier to grep for DB_ in your code
anyway).
> This works fine as long as you don't have functions that return negative
> integer values. By the way I don't like the idea that return types
> suddenly change.
PHP has lots of functions with "mixed" return types. I like your
suggestion, but I think the created error objects should be returned.
That is the only way the user can catch and handle the errors.
> Another point is that each module has to provide certain functions to
> deal with the exceptions. In DB you can find isError(), isWarning(),
> ErrorMessage() and lots of define calls. Does every PEAR module provide
> these functions, could we derive every PEAR module from a PEAR base
> class where these functions reside? Yes, we could, but it does not solve
> the underlying problem.
>
> How does PHP itself handle this situations? PHP sometimes stops
> execution, sometimes returns false and sometimes return 0 or "" or an
> empty array. It always displays an error message unless you supress it.
> I think we can't do better but simulate this behaviour.
IMHO, stopping execution and displaying an error is a very clumsy way of
handling errors, we should try doing better. The best thing would be to
have real exceptions, the second-best is to return error objects.
> With the sketched modell it's up to the module designer which way to
> take.
>
> +++ throwing exceptions that can't be caught +++
>
> class foo {
> /**
> * @return int $foobar
> */
> function bar() {
> [...]
> if (false == $ok)
> new pear_notice("Note from bar()", 1, __FILE__, __LINE__);
> [...]
> return $foobar;
> }
> }
>
> $foobar = foo::bar();
>
> This notice can't be caught, but the user can override
> pear_exception_handler::handleNotice() to define what happens with the
> note.
>
> +++ throwing exceptions that can be caught +++
>
> class foo {
> /**
> * @return mixed $foobar returns an integer on success, an error
> message on failure
> */
> function bar() {
> [...]
> if (false == $ok) {
> $err = new pear_warning("Warning from bar()", 2, __FILE__,
> __LINE__, false);
> return $err->get();
> }
> return $foobar;
> }
> }
>
> $foobar = foo::bar();
>
> A warning is created, but not automatically handled. Usually it would be
> display on the screen, the script would continue.
>
> +++ throwing exceptions that stop execution +++
>
> class foo {
> /**
> * @return int $foobar
> */
> function bar() {
> [...]
> if (false == $ok)
> new pear_error("Panic!", 3, __FILE__, __LINE__);
> return $foobar
> }
> }
>
> $foobar = foo::bar();
>
> An error is created and automatically handled. The message would be
> displayed, excecution stops.
>
> +++ what can be modified by the user? +++
>
> The user can override the default behaviour of any kind of exception.
>
> He might want to change the way a warning is displayed and send the
> warning via e-mail. To do so the user writes a new method
> pear_warning::handleWarning() and overrides
> exception_handler::handleWarning().
>
> <?php
> function handleWarning() {
> if (!$this->show_warning)
> return;
>
> $msg = sprintf("s***, there's a warning in %s (line %d): '%s'",
> $this->file,
> $this->line,
> $this->message
> );
>
> @mail("ulf@redsys.de", "warning in ".$this->file, $msg);
>
> print $msg;
>
> if ($this->halt_on_warning)
> die();
> }
> ?>
>
> Maybe the user wants that script excution always ends, even on notes. To
> do so you the user defines an instance var pear_notice::halt_on_notice
> and sets it true to override pear_exception_handler::halt_on_notice.
>
> As you can see it's not perfect, but it's a good compromise.
>
> We would get rid of:
> - lots of defines
> - error handling functions within a module
>
> We would get:
> - five basic exception (notice, warning, error, io, runtime)
What is really the distinction between a runtime error and others when
the script is running? :-)
> - default behaviours
> - configurable behaviours
My main problem with your exceptions is that they act like signals, but
without returning control to the interrupted function. I want to be
able to write code that is something like this:
$res = $dbh->query("INSERT INTO names VALUES(?,?)",
array($id,$name));
if (PEAR:isError($res)) {
if ($res->errorCode == DB_ERROR_CONSTRAINT) {
print "$name ($id) is already in the database";
} else {
log_error(3, $res->errorMessage());
print "some error occurred, please talk to the
administrator";
}
}
I have a problem with defining error handling functions, since they give
the user less graceful degradation when an exception occurs. But we can
have a compromise: the user should be able to configure whether he wants
to have "in-lined" error handling like in this example, calling an error
handling function (or object+method), or to print the error and
optionally stopping execution.
- Stig