Re: Re: PEAR_Exception in CVS
| From: | Hans Lellelid | Date: | Fri, 02 Jul 2004 03:05:30 +0000 |
| Subject: | Re: Re: PEAR_Exception in CVS | ||
| References: | 1 2 3 4 | Groups: | php.pear.dev |
| Request: | Send a blank email to pear-dev+get-31478@lists.php.net to get a copy of this message | ||
Hi Alan et al.
Alan Knowles wrote:
This thinking off the top of my head a bit, In general, PEAR_Exception at present is nice and simple, and looks like a good lightweight solution for most exception purposes. Missing from it: a) printf() type messages for arguments: (needed to enable translatable messages)Is this really necessary? Exception messages should never be shown to an end user, IMO. You would catch an Exception of a particular type and then display an error if that was desired: } catch (DBException $e) {
Request::redirect('/to/localized/error_page.html');
}
Exceptions should be dumb simple objects. The messages in them should
be useful for developers debugging a problem. If a particular project,
we'll call it TowerOfBabel, has developers that don't speak a common
language, then they could implement gettext (or other) translation in
their TowerOfBabel_Exception. My POV is that translation is for end
users; Exceptions are for developers. Is PEAR also adopting policy that
API docs are to be translated? To me it's the same question.
b) context exceptions (eg. per package) Possible solution:? MyClass_Exception extends PEAR_Exception { } or is this needed? - as debug_backtrace can grab the classname of the calling class?Yeah, I'm not entirely sure what "context" means still. To me what Greg means by context sounds like something that you describe in the message. Exceptions have very readable stack trace and PEAR_Exception even has ability to nest other exceptions (and display them in readable way too). You do still need subclasses because broad categories of exceptions (db, i/o, etc.) need ability to have specialized types of handling. For fine-grained handling control you can use the CODE, but that is much more painstaking than using catch blocks: } catch (DBException $sqle) { // do stuff that matters when db errors happen } catch (Exception $e) { // do sutff that matters when other errors happen }
c) Stack? Could this be implemented seperately as a observer?Sure, absolutely. It could be stored internally too, but I think the observer route is better because I don't know why people would want stacks as a rule when things are thrown. Throw-based error handling is rather different from stack-based error handling. If you throw an exception the idea is "eject! eject!" and either it is handled nicely by calling code or it is re-thrown on up -- until the user gets a nice friendly error page. There's not a lot of need for stacks in that model. If you are accumulating exceptions in a stack then you are probably doing something with exceptions that [most agree] you shouldn't (i.e. using exceptions as flow-control).
d) Warnings etc. - just done by returning PEAR_Exception or a special contructor that flags the object as a warning? return PEAR_Extension::warning(....); (and hence MyClass_Extension::warning(....); )I think for warnings the stack model is perfect. Because it's passive. You don't want your code forcing warnings down the user's throat when the user may (will probably) simply not care. Using return types forces users to check the return value of any method that might raise a warning or call a meathod that would raise a warning. That's a huge pain. Yes, I know that's how it works now for PEAR_Error, but the idea is that better things are possible. When returning use Exception ... I think that should just be a rule of thumb; if it's important enough to warrant requiring the user to do a type check & handle then it should be important enough to throw & require the user to catch. No? Certainly you could use Exception derived objects to store warning information. Exception objects themselves are, of course, well suited to this. This is not "using Exceptions for handling warnings" but rather using a stack model that contains Exception based objects. One advantage to that approach is that it solves the problem where in some cases something should be an Exception -- i.e. THROW! -- and in others it should be a warning. I think what I hear myself advocating is something like PEAR_ErrorStack afeterall. Specifically for warnings & notices classes *may* implement an interface like IRaiseWarnings, IRaiseNotices that prescribes methods like ->getWarnings(), ->hasWarnings(), ->getNotices(), etc. You could have special PEAR_Warning class that extends Exception that holds these warnings/notices or you could just use PEAR_Exception -- or even Exception. Having these objects extend a built-in PHP class would be nice since then other non-PEAR packages don't need to concern themselves with the API of yet another PEAR lib unless they want the added functionality. FYI, I'm pulling this idea pretty much right out of Java. For example JDBC: conn.getWarnings() stmt.getWarnings() rs.getWarnings() ==> i.e. stack model for warnings. Exception \-SQLException \- SQLWarning
\- DataTruncation
(could be thrown as Exc or pushed onto stack as warning)
Of course, in Creole I ditched this method & opted for trigger_error w/
E_USER_WARNING user level. PHP core is already raising WARNINGS so any
production application is gonna have an error handler. Works perfect.
The question I have about the stack model is this ...
If I have an library that makes use of multiple other libraries, how do
I make the stack checking transparent for the end-user (so that they can
make one getWarnings() call to get all warnings that happened from all
packages)? As I understand it, every lib would have it's own error
stack, right? Or is there a global error stack that keeps everything?
It didn't seem so, but maybe I missed something. Perhaps the official
solution is for TOPLib to check for warnings in all CHILDLibs and add
them to its own warning stack? (Seems wrong & a bit wasteful since the
user may well not care.)
Cheers,
Hans