Exceptions were sneaked into core without agreeing on their use. What's worse, there was no research on when they are necessary and what problems they bring. We currently have two problems: if an exception gets thrown too early then Drupal dies and there is an issue which would solve by adding even more code to bootstrap (the error/exception handling). The bigger problem is if an exception gets thrown while handling an exception (say, you make a typo in a query in catch which resets some state) then you get a very helpful Fatal error: Exception thrown without a stack frame in Unknown on line 0 error message.
Instead, we should collect errors in a static and provide a getter. Very easy with drupal_static. This pattern is very common in PHP and Drupal and the consequences are well understood. We should throw an exception only if there is no hope of continuing.
Comment | File | Size | Author |
---|---|---|---|
#17 | exceptions.patch | 2.83 KB | chx |
Comments
Comment #1
Dries CreditAttribution: Dries commentedThe fact that we get
Fatal error: Exception thrown without a stack frame in Unknown on line 0 error message
is that a bug in PHP or Drupal?Comment #2
chx CreditAttribution: chx commentedIt's a PHP feature! :) Edit: http://bugs.php.net/bug.php?id=36826
Comment #3
casey CreditAttribution: casey commentedThrowing exceptions in a exception handler doesn't seem the best thing to do to me.
Comment #4
sunAlthough I'm not very familiar with the problem and exceptions in general, the outlined problem analysis + proposed solution sounds sane. So, a +1 from me.
Comment #5
casey CreditAttribution: casey commented-1 from me. Use of exceptions is a very powerful method of error handling. Pushing errors in an array doesn't give you very much room to fix/handle those at runtime.
Throwing exceptions in catch blocks work fine, just not in a exception handler. A exception handler is a ultimum remedium; it catches exceptions which are uncaught by PHP script. You shouldn't throw exceptions in there.
Comment #6
yched CreditAttribution: yched commentedAgreed that a static array of errors doesn't provide the catching features of exceptions.
Field API form validation, for instance, entirely relies on raising / catching exceptions.
Comment #7
jbrown CreditAttribution: jbrown commentedI disagree chx. Exceptions are extremely powerful when used correctly.
There should be an exception handler, but it should never be used deliberately. It is a bug if it is called.
Functions should document any exceptions they may throw.
Functions that call such a function should catch these exceptions, or document that they may throw them.
Comment #8
jbrown CreditAttribution: jbrown commentedExceptions fall through the call stack until caught:
It is only if they reach the bottom that the handler is called in.
Comment #9
Andrew Udvare CreditAttribution: Andrew Udvare commentedThis snippet will cause a fatal exception most of the time if the record already exists. Bad if you want to keep refreshing the page for testing.
Also, forgetting to call db_set_active() after switching databases will often do the same.
Comment #10
chx CreditAttribution: chx commented@jbrown did you even read my writeup? Noone cares what the intentional purposes of exceptions are. I am worried about the known and unknown side effects.
Comment #11
Crell CreditAttribution: Crell commented@Tatsh: Both of what you describe are bugs in their own right that should be fixed. (The latter is a bug in the caller's code. You'll get an explosion if you try to run Drupal queries against a non-Drupal DB because the tables are missing. That's to be expected. If you really want to be safe, use Database::getConnection() to get your 3rd party connection and use it directly, without ever switching the active DB.)
Comment #12
jbrown CreditAttribution: jbrown commentedchx: provided my rules in #7 are followed, there are no side effects.
Comment #13
catchI recently got the stack frame on line 0 error when dbtng was querying for a non-existent database column. In D6 you'd get a nice error showing you the query, so this is still a critical regression.
Comment #14
jbrown CreditAttribution: jbrown commentedcatch: see #742246: Handle uncaught exceptions
Comment #15
jbrown CreditAttribution: jbrown commentedDemoting this to normal to bring down the critical issue count as #742246: Handle uncaught exceptions has been fixed.
Comment #16
andypostSuppose _drupal_log_error() should care about switching DB to 'default' database other than current implementation of dblog_watchdog() which allows only storing messages in default DB
Comment #17
chx CreditAttribution: chx commentedIn Drupal 6 database errors were not fatal. Nor they should be. Note that once this is in we can happily throw out drupal_register_shutdown_function and whatever else kludges we added because of this regression.
Comment #19
matt2000 CreditAttribution: matt2000 commentedComment #20
matt2000 CreditAttribution: matt2000 commentedConfirming that install fails:
Fatal error: Call to a member function fetchField() on a non-object in /var/www/drupal/includes/bootstrap.inc on line 678
Comment #21
Damien Tournoud CreditAttribution: Damien Tournoud commentedStrongly disagree. Database errors should be fatal. We already had trouble with that before, it's way better to fail quick on this.
Comment #22
chx CreditAttribution: chx commentedDamien, this causes uncounted problems. As I mentioned, so far we have broken installs and session dying with uncaught on line 0 and then who knows what else.
Comment #23
Crell CreditAttribution: Crell commentedAbsolutely not. Exceptions are the main way that we trigger transaction rollbacks. Requiring that we explicitly ask for a transaction every time we think we may possibly need one renders the entire error handling system useless.
Silently failing (which is what returning NULL means) is a terrible idea. It means every time you get a result object back you need to check it's type before using it to confirm that it's not NULL or you get a fatal anyway. (See comment #20, for instance.) Exceptions give you a chance to recover gracefully if you plan for it. If we're not planning for it properly, the solution isn't to throw out exceptions (pun intended) but to handle them properly.
Comment #24
chx CreditAttribution: chx commentedAs I said already: I will point everyone to this issue when they come to IRC and post everywhere how Drupal 7 sucks because of it. Your call. This is a very bad decision but I cam not fight both of you. I really like how theories and transactions (which are absolutely unnecessary for the typical webapp and only throws hurdles in your way when you try to scale) stop making Drupal better. Oh well.
Comment #25
jbrown CreditAttribution: jbrown commentedExceptions are only fatal if they are not caught.
If you want to handle a db error in code instead of getting the error page, just wrap your code in a try{} catch{} .
I never noticed that throw_exception option before - its really awful and should be got rid of. Use try{} catch{} instead when necessary.
Comment #26
matt2000 CreditAttribution: matt2000 commentedIf database errors are (intentionally) fatal, is it still possible for someone to write a module that would respond to database failures by serving a page from a static cache (such as provided by Boost module or a proxy) ?
Comment #27
joshk CreditAttribution: joshk commentedComing in six months late and with my Pragmatic hat on I think this is a must-fix.
The Drupal developer experience is 100% broken if database errors (or who knows what from contib) cause fails like this:
#742246: Handle uncaught exceptions may have helped but I have hit this enough times in my first attempt to do an actual upgrade. Personally I would consider this as a critical issue. Nobody cares whether we use exceptions "correctly" or not, but they will walk away from the project if debugging becomes a complete guessing game.
Comment #28
joshk CreditAttribution: joshk commentedSo as it stands, it looks like we have some cases from #742246: Handle uncaught exceptions where error_displayable() fails, which causes this problem. Investigating...
Comment #29
joshk CreditAttribution: joshk commentedOk, this isn't about the database in particular. I'm going to re-close and open a new issue.