Http Error 500, Server error page concept. Man holding banner with error message. Web technology series.

Structuring PHP Exceptions

I seem to constantly work on improving my habits regarding the use of exceptions. I think it is an area that I haven’t yet fully explored, and it is very difficult to find anything more than very basic explanations and tutorials online. While the consensus is to use exceptions, there is very little information on how to structure and manage them in a larger codebase. The larger and more complex your projects become, the more important it is to start with a proper structure to avoid expensive refactoring later on. Your client will surely be thankful!

In large #PHP projects, start with a proper structure to avoid expensive refactoring later on. Click To Tweet

In this article, I want to talk about the way I currently set them up and use them in PHP, in the hopes to spark some discussion on the topic and get further feedback.

Why Even Use Exceptions?

Before discussing implementation details, I think it is necessary to mention what the main benefit of exceptions is when compared to something like trigger_error.

Normal PHP errors and warnings come from the procedural world, and they provide one central mechanism to deal with these errors, a function you declare as being the error handler through the set_error_handler method. Apart from being able to set different error handlers for different levels of errors, you have no further way of controlling the point where you can deal with your errors. The error handler is somewhat outside of the context of you current execution flow, so it is very difficult to do anything meaningful to recover from the error once you’ve reached that point.

Exceptions, on the other hand, can be dealt with at any point in your code. And, as they escalate throughout your different layers of code, you can decide for each exception at which layer and in which context you want to deal with them. This allows you to catch and gracefully handle exceptions directly in the calling code when this makes sense, and let them bubble to the surface if not.

As an example, when your code that fetches an entry from the database throws an exception, you can handle this in a nuanced way based on the type of the exception. Did the database not return a result because that ID was not known? Maybe return a NullObject instead of throwing an error. This will let a user continue working with the system without getting fatal errors. If the connection could not be established, however, we might want to have our exception bubble up to the infrastructure layer to immediately point to a bigger issue.

Build Upon SPL Exceptions

The Standard PHP Library (SPL) provides a predefined set of exceptions that I would recommend you to build upon. These provide a generalized classification and having your own exceptions extend these makes it easier for consuming code to catch them. The consuming code can, for example, choose to catch the general group of RuntimeException, which would include standard PHP exceptions as well as your own extensions of this.

For my own components, I have a standard set of exception groupings I pull in via Composer that mirrors these SPL exceptions while adding an interface to them that is specific to my component’s organization. All of my custom exceptions then extend one of these.The point of adding this additional layer of exceptions is to have one additional way of filtering what exceptions I want to catch. I found this to be needed when you work in a codebase where project code is built on a framework, and that framework is built on individual packages.

Every base exceptions in that standard set both extends one of the SPL exceptions as well as implements the BrightNucleus\Exception\ExceptionInterface interface. This then effectively gives me a way of only catching “Framework-specific” exceptions targeting  from within any of my code, by targeting that interface.

Here’s a quick summary of how to catch exceptions at different granularities:

  1. Catch all exceptions
    catch( Exception $exception ) {}
  2. Catch all exceptions thrown by a Bright Nucleus library
    catch( BrightNucleus\Exception\ExceptionInterface $exception ) {}
  3. Catch a specific SPL exception (BrightNucleus or not)
    catch( LogicException $exception )
  4. Catch a specific SPL exception thrown by a Bright Nucleus library
    catch( BrightNucleus\Exception\LogicException $exception ) {}

As you can see, we cover layer-specific catching as well as type-specific catching with such a structure.

Naming Conventions

My current take on this is to name the exceptions differently based on whether they represent a specific error to be acted on or a group that other exceptions should extend to further qualify.

So, as an example, consider having a piece of code that tries to load the contents of a file, and that has three different ways of failing:

  1. The file name is not valid.
  2. The file was not found.
  3. The file is not readable.

I would build the following exceptions to make this semantically clear:

FileNameWasNotValid extends InvalidArgumentException
FileWasNotFound extends InvalidArgumentException
FileWasNotReadable extends RuntimeException

The groups have the Exception suffix, as their naming reflects a “group of exceptions”. The specific exceptions that need to be thrown don’t include that suffix, though, but rather are formed by building a past-tense sentence from the error condition that has happened.

When exceptions are named in this manner, together with the concept explained in the next sections, reading the code becomes much clearer, as you are almost reading normal sentences.

Named Constructors Encapsulate Exception Logic

Most developers tend to construct the exceptions right where it happens. This often results in methods where the exception-throwing part actually has more lines of code than the actual logic. Reading code like that is very cumbersome, as you need substantial effort to identify what the important statements are.

I recommend building named constructors for your exceptions, so that the actual operation of preparing the arguments for instantiating the exception are encapsulated within the exception code, and do not pollute your business logic more than necessary.

Use Named Constructors for your #PHP exceptions to keep your business logic clean. Click To Tweet

As an example, let’s consider this piece of code:

public function render( $view ) {

   if ( ! $this->views->has( $view ) ) {
      $message = sprintf(
         'The View "%s" does not exist.",
         json_encode( $view )
      );

      throw new ViewWasNotFound( $message );
   }

   echo $this->views->get( $view )->render();
}

As you can see, the code for dealing with the exception is more complicated than the actual logic. To remedy this, include named constructors in your exceptions, like the following:

class ViewWasNotFound extends InvalidArgumentException {

   public static function fromView( $view, $code = null, Exception $previous = null ) {
      $message = sprintf(
         'The View "%s" does not exist.",
         json_encode( $view )
      );

      return new static( $message, $code, $previous );
   }
}

You can have multiple named constructors within the same exception, depending on what context they should be instantiated in. Basically, you’ll have one named constructor for each distinct message.

Now, rewriting the previous business logic to use this named constructor makes the code much cleaner:

public function render( $view ) {

   if ( ! $this->views->has( $view ) ) {
      throw ViewWasNotFound::fromView( $view );
   }

   echo $this->views->get( $view )->render();
}

Much nicer, don’t you think? Apart from the code being cleaner to read, we’ve also put the actual string to use as message within the Exception itself, which is easier to maintain.

Localized Exception Messages

In some instances, it might make sense to allow your exception messages to be localized through gettext. However, I would advise against doing this as a general habit, as it comes with disadvantages as well.

Localizing the exception messages makes sense for a group of exceptions that is meant to be directly used to provide feedback to the user at the front end.

Although exceptions should not generally be directly used at the front end (since they should be exceptional, by their very nature), this sometimes might make sense. In such a case, localizing your exceptions is easily done by wrapping the string within your named constructors into gettext functions.

The main disadvantage is that exceptions are often searched for through their message string, by developers/sysops in log files, and by users in search engines. Localized messages break such a search strategy. If no other identifier is provided (exception name, exception code), it is very difficult, especially for users, to find out what is going on.

Localized exception messages will make it harder for your users to 'google' for solutions. Click To Tweet

Catching Exceptions

It sounds very obvious, but it is actually pretty difficult to do in practice: Only catch the exceptions you can directly handle within your current context.

So, if your intent is to do an operation in a fail-safe way, and return a NullObject in case something goes south, it is perfectly okay to just generally catch( Exception $exception ) {}. However, if you are trying to execute an operation that needs to be completed successfully to maintain the integrity of your system, pay close attention to only catch the exceptions that you are actually able to properly remedy. Otherwise, you might prevent a more severe exception to bubble up to the top, and effectively “hiding” an issue within your system.

In most cases, you should differentiate between logic exceptions and runtime exceptions. That’s why the SPL exceptions we’ve seen before provide these two types as their upper-most level of distinction.

Logic exceptions are exceptions where you as a developer are currently doing something wrong. You are asking for values that cannot exist, call methods with the wrong type of argument, etc… This is stuff that needs to be dealt with immediately during development. In a perfect world, a logic exception would never make its way to the production environment.

Logic exceptions should never make their way to your production environment. Click To Tweet

A runtime exception, however, is an error condition that you have no control over during development. A database connection getting blocked by the firewall, a file permission that is incorrect, etc… These errors are unavoidable. You can not “develop a system where the database cannot fail”. What you can do is “develop a system where a failed database connection produces a nice error message and alerts the system administrators, instead of throwing a fatal error”.

Your code cannot "never fail", but it can "only ever fail gracefully". Click To Tweet

This is why you should make sure to catch runtime exceptions at some layer in your system (the exact layer depends on many factors), and let logic exceptions pass through so that they throw obvious error messages for the developer.

Keep in mind that you can provide multiple catch clauses, and an exception will be compared against each of them in order as long as no match was found yet.

Central Error Handler

To not just take the web server down for the exceptions you let through (whether that was intended or not), you should provide a central error handler that catches any remaining exceptions that haven’t been caught up to that point.

At the very least, you should log these exceptions and their stack trace, so that you can analyze what has happened after the fact.

I recommend using something like BooBoo to wrap your entire system into such a central error handler.

Provide Your Insights

This was a quick run-down of how I am currently using exceptions. I don’t think I’ve properly mastered them yet, though. I welcome any feedback or insights on how you use exceptions in your projects and specific issues you’re facing. So please go ahead and join the discussion in the comments!

18 comments

    • Alain Schlesser says:

      Hey Nikola,

      Thanks for the link! We’re pretty much covering the same ground, aren’t we? Interesting to see the same topic covered by different people, will certainly further help for others to understand what this is all about.

      Also, I had never bothered to look for a name for what you call the “Marker Interface”, so I learned something new as well!

      Cheers,
      AlainReport

      • Nikola Poša says:

        Definitely, exceptions and error handling are often neglected aspects of development, and there are very few resources like these two that provide comprehensive guideline on how to approach this matter.

        Keep up the good work!Report

  1. Dylan Kuhn says:

    I think exceptions are difficult in part because they brush up against some deep truths that we often try hard to hide from:

    There are often many more exceptional cases to handle than our original intended case. Correctly handling all cases can drastically obscure the clarity and intention of our code.
    Our application probably has a multitude of dependencies that are provided by diverse entities: developers of various flavors, users of many roles, hardware, networks, services near and far, etc. An exception due to a missing dependency might demand attention from any one of these, but it’s not often easy or clear how to get the message to them or even who the relevant entity is.
    Many components of our application probably use different approaches to exceptions, and it’s overwhelming to handle all of them consistently.

    You’ve made some progress on some of these problems, more than me, but there is a long way to go to establish best practices, and maybe this is why it is hard to find them. I have this feeling that the best behavior of an application is to check dependencies as thoroughly as early as possible when the entity supplying the dependency is available to make corrections. Of course even a properly supplied dependency can fail later, but getting them right initially would go a long way.Report

    • Alain Schlesser says:

      Hey Dylan,

      Thanks for your insightful comment!

      I agree, there are always more ways for your code to fail than you can anticipate.

      I normally try to have several layers in my code, and “clean up” before crossing layers. So, for example, loading a template might involve several subsystems and dependencies, and each of these can fail. I try to handle them gracefully within the template loading code wherever I can to provide a usable template whenever possible. But then, I wrap the entire thing into a try/catch block to catch whatever I did not anticipate or could not handle properly, and send a generalized FailedToLoadTemplate exception, with the caught exception attached as the reason.

      The goal is to simplify at every layer boundary, and have all the API interactions either succeed, or only throw one or more very specific exceptions that have been documented.

      After all, once the loading has failed within the template loading library, the consuming code could not do much with a precise error message. It just wants to know whether to proceed or not.

      So, I pretty much “reset” the error handling paths / complexity at each layer boundary, and swap them for a known and documented set of exceptions that are then considered part of the API.

      Cheers,
      AlainReport

  2. Error handling… Among the worst accomplished basic tasks, together with date handling and text encoding.

    When I look back upon my earlier code I realise how much I’ve learnt and I reckon I would do things rather differently today, but in general it’s only code of its time and I don’t normally find terrible mistakes… except when it comes to error handling. Almost every piece of code I’ve ever written to deal with errors and help in development eventually had the opposite effect. I came to a conclusion: it you don’t know what you’re doing, it’s better to just not write error handling code at all—at least you can benefit from system-wide handlers.

    Thank you very much for this article. I came across it when I was putting together an error handler for a third-party micro-framework (happily, actually pretty conforming to your principles) and now I think I’ll just drop it all in favour of BooBoo ;-)Report

    • Haha, yes, I can relate.

      Mess up your code, and you need good error handling… but mess up your error handling, you’re screwed!

      I use BooBoo in production attached to Monolog, and it does this one job really well. Also, what really helps is define specific “layers” as I had written above and make sure you properly control what exceptions might pass from one layer to the next, by having a general catch with an eventual rethrow of a different exception at the boundaries of these layers.

      Have fun messing up the next error handler, and share your findings! We all can learn a lot still when it comes to exceptions!Report

  3. Hi Alain,

    Great article. I just wanted to ask you you about a remark you made: “Although exceptions should not generally be directly used at the front end (since they should be exceptional, by their very nature)”.

    I may be putting words in your mouth here, but in almost every article on exceptions this phrase is brought out: “Exceptions should be exceptional?”. What do you mean exactly by ‘exceptional’? And why are they less preferable than that their most obvious alternative: an error object? (I’m deliberately ignoring null objects here, which may, in context, be better than exceptions or error objects – but I consider these a fundamentally different approach to error handling).

    You specifically mentioned the front-end, and I assume you’re thinking of cases where user input is being validated – in which case you typically want to handle multiple errors simultaneously (e.g. on a form field, it’s helpful to know all the errors on the form, not just the first one). But if in that instance, is a error object collection any better than a exception containing each of the ‘violations’.

    I personally find exceptions fit with the ‘do don’t ask’ principle nicely. I can simply tell my dependencies what to do and catch any exceptions without having to check their return values. This is little more than personal preference, but there are the other benefits to exceptions that you include in your article.

    In my view, exceptions are not exceptional. They can be entirely anticipated, and common. For me they represent a point in a method’s flow where it does not know how to proceed or it’s isn’t its responsibility. The exception can then cascade upwards until it reaches the appropriate layer to catch it.

    I would, for instance, see no problem in a validation process on a form throwing an exception (containing all the individual violations). I seem to be at odds with a lot of developers, and the mantra that is ‘exceptions are exceptional’, so I’d be very interested to hear more of your thoughts on this.Report

  4. Hi Stephen,

    Ah, good question! I’ll try to explain my point-of-view and refer to your example of user input validation.

    First of all, exceptions being “exceptional” does not mean they should be sparsely used. The “exceptional” quality does not refer to the number of occurrences, but rather to the fact that they are not part of the planned set of execution paths. As an example: If you do a filtered query against the database, you normally have one explicitly planned case of failure, which might even be the very first iteration that is run on the code: the query did not return results. You would not want to throw an exception in this case, you return either an empty collection or a null object. However, there is a potentially unlimited number of “exceptional” ways for this code to break: connection error, out of memory error, invalid query, etc… All of these would normally throw exceptions from the querying code. So, you might even end up with a large number of exceptions. But, in an ideal world, none of these would ever be thrown.

    Another general rule of exceptions is the code that throws them should not assume anything about where they will be caught and handled. It might be the direct caller, but it could also be any other code higher up in the call stack. Just take a look at the language involved: you “throw” an exception, without knowing whether someone will “catch” it or who that might be. There is no direct coupling involved, you always should assume that exceptions will potentially travel through the entire call stack and end up in the log files. In your case, if you intend to use the exceptions to directly control the flow of the application, both parties need to be aware of these exceptions and how they will be handled. You could never just let these exceptions fall through to a higher-level exception handler, as they would not make any sense anymore at that level. You basically replace an explicit interface (objects & typehints) with an implicit convention, that is very brittle. What’s more, think about what you need to do when one of these two parties encounters a actual runtime error. You’ll end up with a confusing set of exception handlers.

    Regarding your user input validation example, I do indeed use a collection with error objects. I am actually right now finishing a generalized form submission handling pipeline, and it uses a response object with an attached error object collection (which might be empty). Responses can both implement a SuccessResponse as well as a FailureResponse. Validation errors (as well as any other errors that need to be notified) get added to a response’s error collection, so that whatever code that gets the response can render these errors. A single submission handler can also throw exceptions, and these exceptions are caught at the pipeline level. When an exception is encountered, the pipeline is aborted at that, and a FailureResponse gets sent back with the exception as one of the errors in the error collection. Exceptions don’t deal with stuff the user did wrong, they deal with cases where the code does not behave as required during runtime.

    Regarding the “Tell, don’t ask!” principle (I assume this is the one you meant), I don’t think your example has much to do with this. If you intend to use exceptions for providing validation feedback, you still need to evaluate what was returned. But you have displaced that evaluation from the normal code execution into the catch block instead. This does not provide an immediate benefit, as far as I can tell, but adds several drawbacks:

    To be able to regroup several errors into one exception, you need to collect these errors first, as you can’t throw an exception collection. So you build an error collection either way (in some form or other) and then use the exception as a vehicle. As you have the error collection readily available, why not build a proper interface for passing it along in an explicit, robust way?
    As the exception is used as a vehicle to transport several errors from one context to another, you still need to iterate over the internal collection of the errors within the exception. But you will need to do this within the catch block (or move it to somewhere else, which might create a problematic execution flow).
    You still need the normal exception handling for unexpected runtime errors, which might end up making your code confusing because of different catch blocks serving different purposes.
    There are more technical considerations as well. Apart from exceptions being slower (in a negligible way), you will probably throw off any branch prediction optimizations by the compiler (not even sure PHP does that, though). Compilers optimize for the “expected” case, not for “exceptions”… ;)

    Hope the above was clear enough. I would love to know what you think about these objections.

    Cheers,
    AlainReport

  5. Thank you for a such detailed response :).

    “There is no direct coupling involved…” This is a very good point. Exceptions create an implicit coupling. I find this reasoning very compelling. But “you always should assume that exceptions will potentially travel through the entire call stack and end up in the log files” – this is true, but is it not a failure of the programmer to properly implement their interface? Exceptions form part of a method’s interface, and if you’re not catching your dependencies’ exceptions then you’re effectively throwing them. Ultimately, in a GUI application at least, you should be ensuring that no exceptions are allowed to bubble to the very top. (I believe in Java you have to explicitly declare if your method throws an exception otherwise it will not compile. But we’re discussing PHP here, so the pragmatist inside me is screaming that you’re right, this strategy is brittle).

    I’m not convinced by the argument that exceptions are slower (they might be, I’ve never done any bench mark tests), but in a web application a single exception would be slower – as you point out – in a negligible away. However, I had not considered the compiler – that’s certainly food for thought.

    But you have a convinced me (at least in a user-input validation sense). However, to pivot slightly, one example I had in mind was an instance where ‘validation’ of the data was a necessary by-product of some action being taken. That is, validation is not simply we need to make sure this data looks right (as you might expect for form submissions, or general data-entry), but that this validation must be correct for the program to continue.

    Consider a booking (for events ;) ) program. A Booking instance is created from the user input. Now clearly there is a number of things that need to be checked before the booking can initially accepted by the system (i.e. ‘pending payment’) or indeed marked as ‘confirmed’. Namely there are constraints referring to ticket availability, and venue capacity.*

    The “Tell don’t ask” principle comes into play as follows: rather than perform validation on the data I simply do: $booking->set_status( BookingStatus::CONFIRMED() ) . The booking would (effectively) then ‘notify’ the event to which its attached, and the event would then be responsible for ensuring that there are no violations. If not, the status is changed, otherwise an exception is thrown (containing all violations: “Ticket X is no longer on sale”, “Ticket Y is sold out”, “Venue Z is full”).

    Why do I think this is preferable? Firstly it’s not the responsibility of the calling code to ‘validate’ that booking. And to do so before trying to instantiate a booking object in the first place would be to duplicate code that would doubtless have to appear elsewhere (when a booking is ‘confirmed’, or “un-cancelled”, for example) – of course you wouldn’t actually duplicate code – but you would still need to remember to call it.

    Secondly, it simplifies the workflow. Rather than validate the data, check the returned value and then try to set the status of the booking, I can simply set the status. I shall be wrapping the commands inside a try block anyway – and this keeps the code inside the try block minimal.

    Thirdly, my error handling is all in the same place, and all together. As you point out you can easily end up with multiple catch blocks, but the advantage is that all your error-related code is together. In a case of a booking form, there’s probably only 1 or 2 different types of exception that need converting to a human-friendly response. The remainders will be those genuinely exceptional cases which require logging, and generic failure message.

    Of course, even this strategy doesn’t necessitate exceptions. An alternative would be for the booking to ask the event to accept the booking’s status change, and check for the event’s response. As you suggest, I could have a “proper interface for passing it [error object] along in an explicit, robust way”. But this would involve a number of classes (Booking, BookingStatus, Event) passing error objects to each other in a way that replicates the flow of an exception being called, but requires you to remember to check for error objects and pass them up (and without the aesthetics that exceptions bring and also requires). Exceptions in this instance just seem to be the native language way of doing this: it enforces the desired behaviour, and with less code.

    To summarise my point, you’ve convinced me that for data-validation exceptions do not add any value, and also bring some disadvantages. But I wonder if when data-validation lies deeper down in the business domain, the benefits outweigh the disadvantages

    I hope that explains my view point sufficiently clearly. I’m relatively new to OOP, and so I’m trying to be critical of my own, and others’ code, as well as ‘best practises’.

    (*Admittedly, over-booking is arguably exceptional: You would have client-side code to prevent users from booking more places than there are spaces, but one can imagine a workflow in which an administrator tries to manually confirm a booking for a sold-out event – I wouldn’t consider that exceptional ).Report

    • Hey Mike,

      Without going into too much detail, I’d like to make the following observations regarding the article you posted and some of the comments/links it contains:

      1. The argument “it sucks if used incorrectly” does apply to pretty much any language construct.
      2. Exceptions per se are not meant to handle errors. Errors that can be handled locally should be handled as soon as possible. Exceptions can be better seen as a transport mechanism, to move error information from a layer that can’t handle that error to all the other layers in a cascade, in the hopes that one of these can handle the error at that higher layer.

      3. Having layered code as referenced at 2. presumes that you have both a.) complex enough code and b.) the technical means to separate layers from each other. Both point towards object-oriented code as being the best fit for using exceptions, as procedural code can’t properly deal with either high complexity or clean isolation.

      4. Java is an ill-suited example for discussing exceptions, as that particular implementation is known to be designed in a “controversial” way, especially regarding “Checked Exceptions”, a concept that does not exist in PHP.

      5. I never advocated for exceptions being used for normal execution flow, and I agree it is a bad idea.

      6. Exceptions are not meant to be handled in a 1-to-1 relationship kind of way, where every exception you create needs to be handled by a very specific handler you also create. The point is to just “throw” the exception and assume it will be handled wherever it is most appropriate.

      7. Not having exceptions creates code where ever single function ends up having more error handling code in if/else clauses than actual logic. See pretty much every procedural code ever (including WordPress, with its WP_Error|false|null checks across all the code).

      So, yes, I know that some people loathe exceptions and don’t intend to use them. That’s fine. I would argue though that this is mostly a problem of using the tool in the wrong way (using it like procedural error handling) and/or in the wrong context (using it in procedural code).Report

      • Hi Alain,

        Thanks for the detailed reply.

        "The argument "it sucks if used incorrectly" does apply to pretty much any language construct."

        That is true, but quoting that implies that he did not follow up with the following statement in that same post (emphasis mine):

        "If I call a function and it throws an Exception, then I'm presumably expected to handle that exception case in some manner, to resolve the error. However, if I could have done that, then I probably should have done it to begin with, and if I was capable of eliminating the error possibility, then I don't need to handle the exception case anyway. Meaning that all real Exceptions in the world end up going back up the call stack and just presenting some error to the user. So when Exceptions are useful, then they're useless. By design."

        Moving on…

        "Exceptions per se are not meant to handle errors. Errors that can be handled locally should be handled as soon as possible."

        Very much agreed.

        "Exceptions can be better seen as a transport mechanism, to move error information from a layer that can't handle that error to all the other layers in a cascade, in the hopes that one of these can handle the error at that higher layer."

        That is the theory, yes.

        However when one starts to actually look at use-cases and examples (I am coming to the conclusion that) the theory does not hold up. And BTW, I first learned and became excited about exceptions back in the late 80's when reading Object-oriented Software Construction (OOSC), still one of the best books on the subject IMO.

        I never advocated for exceptions being used for normal execution flow, and I agree it is a bad idea.

        Since your comment I've reread your post twice, and no where in the post did I get that takeaway. It feels you are implying that exceptions are good and standard and should be used frequently in code. Nor did I find any caveats. At least that is how it read to me. Hence why I commented.

        Exceptions are not meant to be handled in a 1-to-1 relationship kind of way, where every exception you create needs to be handled by a very specific handler you also create. The point is to just "throw" the exception and assume it will be handled wherever it is most appropriate."

        That's exactly the point. When is throwing an exception in your own code actually a good idea?

        Clearly there are two sides of exceptions; (1) throwing and (2) catching. If you call PHP library code that throws an exception then clearly you need to catch the exception; that's not what I am discussing here.

        The question is: "When, really, should you throw an exception?"

        For every example I can think of I come to the conclusion that it would be better to simply return an error flag from the function from which you would otherwise throw an exception, e.g. a WP_Error in WordPress for example.

        Let's take your ViewWasNotFound example. Per OOSC an exception is "a run-time event that may cause a routine call to fail." But the view not being found is almost certainly not a runtime error, it is a logic error.

        Returning an error object and checking for the return value makes the most sense to me because it is clear when you call the render() function that the passed view might not be found; deal with this then. Otherwise use a trigger_error() if you are just going to let it bubble up to the top anyway.

        This is especially true for WordPress where WordPress does not incorporate a top level try..catch construct so your unhandled exceptions will "fall on deaf ears" anyway.

        "Not having exceptions creates code where ever single function ends up having more error handling code in if/else clauses than actual logic. See pretty much every procedural code ever (including WordPress, with its WP_Error|false|null checks across all the code)."

        But I am not sure that is anything more than an excuse for not writing robust code?

        Yes, it is nice and convenience to just ignore any potential errors. But writing code where you know what the errors are likely to be but instead punt on errors means that other code that does not know what the errors are likely to be will have to handle them, and that feels like irresponsible and non-robust coding to me.

        Granted, I may not be considering all use-cases and you might convince me otherwise, but currently I am leaning heavily towards the opinion that exceptions should only ever be caught but never thrown.

        "I would argue though that this is mostly a problem of using the tool in the wrong way (using it like procedural error handling) and/or in the wrong context (using it in procedural code)."

        Given both our comments above I don't see where writing good solid OOP code will change any dynamics mentioned. What am I missing?

        P.S. Sorry to be a contrarian here, but you did solicit "any feedback and insights." :-)Report

        • Hey Mike,

          If I call a function and it throws an Exception, then I’m presumably expected to handle that exception case in some manner, to resolve the error. However, if I could have done that, then I probably should have done it to begin with, and if I was capable of eliminating the error possibility, then I don’t need to handle the exception case anyway. Meaning that all real Exceptions in the world end up going back up the call stack and just presenting some error to the user. So when Exceptions are useful, then they’re useless. By design.

          There’s a flaw in that logic. You very specifically throw an exception if you cannot resolve the error condition. Otherwise, it would still be an error condition, but it would not be an exception. Using exceptions does not exclude using other error handling mechanisms when appropriate.

          Also, exceptions going back up the call stack does not mean that they will inevitably be shown to the user (in fact, exceptions should never be shown as is to the end user). There should be other layers, for example, between the DB code and the user, that might all be able to handle the error.

          Since your comment I’ve reread your post twice, and no where in the post did I get that takeaway. It feels you are implying that exceptions are good and standard and should be used frequently in code. Nor did I find any caveats. At least that is how it read to me. Hence why I commented.

          I agree, I did not go into too much into the details of when not to use exceptions. I assumed a general knowledge about exceptions and the willingness to use them when writing the article.

          Very generally, with every language construct, the main caveat is to use it for what it was intended for. You shouldn’t use an Exception to build normal conditional code (and replacing if/else) just as you shouldn’t use a Class to build naming-collision-safe procedural code (and replacing the namespace). Exceptions are meant to signal either logic or runtime error conditions that cannot be dealt with locally to outer code. If used in that way, I believe they are a good and reliable solution to the problem you’re trying to solve.

          That’s exactly the point. When is throwing an exception in your own code actually a good idea?

          Clearly there are two sides of exceptions; (1) throwing and (2) catching. If you call PHP library code that throws an exception then clearly you need to catch the exception; that’s not what I am discussing here.

          The question is: “When, really, should you throw an exception?”

          The answer is quite simple, actually:

          1. throw an exception if you encounter an error condition you can’t immediately deal with
          2. catch an exception only if you can deal with it

          The whole point is that you can throw without knowing who will catch, and that you can catch whatever and wherever you want or need. The error detection and the error handling are decoupled, and the code in-between can completely ignore both.

          With a WP_Error, all the code between the error detection and the error handling needs to be aware of the WP_Error and include additional handling for it.

          Let’s take your ViewWasNotFound example. Per OOSC an exception is “a run-time event that may cause a routine call to fail.” But the view not being found is almost certainly not a runtime error, it is a logic error.

          It can be both. Having set a wrong file name is a logic exception, while having the storage system be offline is a runtime exception.

          Returning an error object and checking for the return value makes the most sense to me because it is clear when you call the render() function that the passed view might not be found; deal with this then. Otherwise use a trigger_error() if you are just going to let it bubble up to the top anyway.

          The point is that you cannot deal with an inexistent view within the rendering code. The outer code that has called the rendering of the view needs to deal with it, and “outer” can be a few layers apart from the rendering in this case.

          This is especially true for WordPress where WordPress does not incorporate a top level try..catch construct so your unhandled exceptions will “fall on deaf ears” anyway.

          Any reliable PHP system (even on a WordPress install) will include a centralized error handler that, at the very least, logs exceptions that were not caught. That simple bit alone will already help make your code much more robust than any if/else blocks you could put within your methods.

          The general approach: Log all uncaught exceptions, provide graceful handling/fallbacks for runtime exceptions, and eradicate all logic exceptions. As stated above, logic exceptions should never make it to your production server.

          But I am not sure that is anything more than an excuse for not writing robust code?

          I personally prefer a robust “architecture” that allows for clean and simple code everywhere in-between. If I need a method to render a view, that method should only care about rendering, not about error handling or giving user feedback when files are missing. Having error handling spread across your entire codebase muddies up pretty much everything you write, and just forgetting one single place somewhere to include this handling will break the code. I don’t call that “robust”, I call it error-prone and barely maintainable at scale.

          Yes, it is nice and convenience to just ignore any potential errors. But writing code where you know what the errors are likely to be but instead punt on errors means that other code that does not know what the errors are likely to be will have to handle them, and that feels like irresponsible and non-robust coding to me.

          The errors are not ignored. They are registered (and probably logged) and passed through the system so that they can be handled at the most appropriate point in the code.

          Granted, I may not be considering all use-cases and you might convince me otherwise, but currently I am leaning heavily towards the opinion that exceptions should only ever be caught but never thrown.

          What do you intend to catch if nothing is thrown?

          Given both our comments above I don’t see where writing good solid OOP code will change any dynamics mentioned. What am I missing?

          I believe that proper exception handling goes hand in hand with a proper OOP, layered architecture. Although you can use the Exception language construct in procedural code, you will not be able to build a smooth handling flow around them with procedural code.

          Exceptions are objects, and are meant to be handled and passed around as objects, extended as objects, and try to solve the problems that procedural error handlers cause in OOP code. That’s why they are a bad fit for procedural code and don’t offer any real benefits there.

          It is just the same thing as arguing against interfaces in a procedural context: “Yes, they suck if used in the wrong way!” ;)

          P.S. Sorry to be a contrarian here, but you did solicit “any feedback and insights.” :-)

          Yes, I welcome any discussions, and huge value can be found in the discussions below the posts. However, I sure hope you’re not just being a contrarian, but have sound reasons to prefer one method over the other.

          Cheers,
          AlainReport

          • All of my comments here about exceptions are within the context of PHP for WordPress. I don't write anything of size in PHP unless for WordPress so I don't feel qualified to offer a definitive opinion outside of WordPress. So if your post applies to use in other frameworks and not in WordPress then accept my apologies.

            Otherwise…

            "There’s a flaw in that logic. You very specifically throw an exception if you cannot resolve the error condition."

            And that is where we are stuck.

            When described in the abstract your assertion is hard to object to. But I am still unaware of any concrete real world use-cases in PHP code where you cannot handle an error condition (except for some edge cases that practically nobody using WordPress ever tackles. Like writing an expression parser.)

            And note I did not say "resolve", I said "handle" because I don't think resolution is in-fact an actual requirement.

            So, how about three (3) use-cases, in a WordPress context, where a run-time exception occurs that you cannot more-appropriately trap and handle by returning a WP_Error? And for this let's ignore for the moment that you personally dislike using WP_Error.

            "There should be other layers, for example, between the DB code and the user, that might all be able to handle the error."

            If the framework (e.g. WordPress) does not provide a top level exception trap then I argue that using exceptions and expecting them to be caught by code that calls your code is irresponsible.

            "just as you shouldn’t use a Class to build naming-collision-safe procedural code (and replacing the namespace)."

            …and I am guessing you chose that example as a subtle dig because you know I generally object to using namespaces for WordPress plugins and themes because of the added complexity and the difficulty of refactoring, no? ;-)

            "Exceptions are meant to signal either logic or runtime error conditions that cannot be dealt with locally to outer code."

            I am repeating myself, but what are three (3) use-cases, in a WordPress context, where a logic or runtime error condition occurs that you cannot more-appropriately trap and handle by returning a WP_Error?

            "The whole point is that you can throw without knowing who will catch, and that you can catch whatever and wherever you want or need."

            And that is my whole point, that throwing errors when you can otherwise trap them seems to me to be irresponsible programming.

            The error detection and the error handling are decoupled, and the code in-between can completely ignore both.

            You can decouple without exceptions, and ignoring errors locally means throwing away the context that you have in your "in-between code" and instead leave it to some unknown caller to make sense of the error. Which is a stretch.

            IMO error handling should happen as close to the source of the error as possible because you know the most about the error at the source, not delegate it to some far away code that someone else might have written.

            "With a WPError, all the code between the error detection and the error handling needs to be aware of the WPError and include additional handling for it."

            And I argue that is as it should be be.

            "It can be both. Having set a wrong file name is a logic exception, while having the storage system be offline is a runtime exception."

            But your example threw an exception even for a logic error, which even Betrand Meyer (OOSC) says should not be handled with exceptions. And he wrote the (initial) book on exception handling!

            Still, when you say "storage system" did you mean the view would need to access the database storage system to display the view, or the file storage system to run the view code?

            If the former I would question why calling a function that either generates the error message or redirects to a URL that says the DB is down is not the better solution? Why is a more complex architecture better when there are simple solutions to deal with things like a missing DB?

            But let us take $wpdb->query() as an example. If the database is unavailable PHP throws uncatchable errors in WordPress 4.7:

            Warning: Error while sending QUERY packet. PID={n} in .../wp-includes/wp-db.php on line 1811

            Warning: mysqli_real_connect(): (HY000/2002): No such file or directory in .../wp-includes/wp-db.php on line 1490

            So using the database storage system being gone as a justification for using exceptions in WordPress is moot (unless WordPress did something like this, which they do not.)

            If the file system, I would argue that you won't be running the code that would throw an exception anyway if you can't access the file system where the code lives.

            "The point is that you cannot deal with an inexistent view within the rendering code. The outer code that has called the rendering of the view needs to deal with it, and “outer” can be a few layers apart from the rendering in this case."

            Yes you can deal with it. Either display an error view in the place of the view that says (something like) "Data is currently unavailable; see your webmaster for more details" or return a WP_Error object and let the code that calls it effectively display the same thing.

            I feel like what I am suggesting is equivalent to recommending unit testing. Yes writing unit tests can be tedious but writing them is how you create a robust system. Some things cannot be easily simplified.

            "Any reliable PHP system (even on a WordPress install) will include a centralized error handler that, at the very least, logs exceptions that were not caught."

            Sounds like a No True Scotsman's argument.

            I could just as easily say "Any reliable PHP system will handle errors as close to the source as they can" but me stating it does not make it any more or less authoritative than your statement.

            But I will give you the exception log! :-D

            "The general approach: Log all uncaught exceptions, provide graceful handling/fallbacks for runtime exceptions, and eradicate all logic exceptions. As stated above, logic exceptions should never make it to your production server."

            I will definitely give you that, but only because you will almost certainly be running someone else's code that throws exceptions. But that does not mean you have to mimic bad behavior!

            (Although good luck with the "never" part! lol)

            "If I need a method to render a view, that method should only care about rendering, not about error handling or giving user feedback when files are missing."

            That sounds good in theory, but in practice, unless you are writing 100% of the code for a solution you cannot depend on other developers to always follow the rules of a strict exception-based architecture when coding for WordPress.

            Postel's law applies here, aka the Robustness Principle:

            "Be conservative in what you do, be liberal in what you accept from others."

            Requiring others to follow your architecture and use exceptions when most in WordPress never do is not what I would call liberal in what you accept from others.

            "Having error handling spread across your entire codebase muddies up pretty much everything you write"

            Well, that is an opinion. I see the error handling and say: "Ah, what a great programmer; they make sure to write robust code."

            "and just forgetting one single place somewhere to include this handling will break the code. I don’t call that “robust”, I call it error-prone and barely maintainable at scale."

            There is no reason you can't have a top level error handler but also seek to handle every error that you can as close to the error source as possible. The top level error handler can be there just in case, not there to actually be used on purpose.

            "The errors are not ignored. They are registered (and probably logged) and passed through the system so that they can be handled at the most appropriate point in the code."

            My point was that you ignored the errors where they occurred.

            And my further point is that the most appropriate point in the code to handle an error is (almost?) always as close to where the error occurred as possible.

            What do you intend to catch if nothing is thrown?"

            Errors thrown by PHP, of course!

            When I said "always catch but never throw" I was assuming we were discussing PHP for WordPress and not writing a language interpreter or compiler. Exceptions are a necessary evil for failed expressions such as divide by zero since the syntax provides no good alternative error handling approach.

            And I would also intend to catch exceptions thrown by lazy programmers for plugins I am forced to use by clients where the lazy programmer decides to throw exceptions rather than handle error where they should by handled; close to the source (and yes that is a dig, but meant only in good humor. :-).

            "It is just the same thing as arguing against interfaces in a procedural context: “Yes, they suck if used in the wrong way!” ;)

            And there is your other dig, you knowing how much I despise PHP's interfaces. ¡Viva la Revolución!

            I sure hope you’re not just being a contrarian, but have sound reasons to prefer one method over the other.

            I can promise you my perspectives are legitimate, especially given I quoted someone's post who I previously disagreed with frequently.Report

          • So if your post applies to use in other frameworks and not in WordPress then accept my apologies.

            I don’t differentiate between WordPress and non-WordPress. Developing with the PHP language should ideally be of equal quality everywhere. The fact that the WordPress Core is written in a rather ancient form of PHP does not mean that your plugins and themes need to be the same. So, what I’ve written applies to PHP code, wherever it is used.

            When described in the abstract your assertion is hard to object to.

            Yes, and creating OOP code is mostly about finding the right abstractions. Specific implementations are easy to code, it is the reusable abstractions that take more experience to design correctly.

            But I am still unaware of any concrete real world use-cases in PHP code where you cannot handle an error condition.

            As soon as you start using OOP code that adheres to SOLID principles, the large majority of error conditions cannot be directly handled where they happen. If your database code does not work because there is no database, it cannot recover by itself, nor can it give feedback to the user. It can only pass on that error and either let someone else handle it/give feedback about it or have the entire request fail. Having your database code render user feedback is not an option.

            You can decouple without exceptions, and ignoring errors locally means throwing away the context that you have in your “in-between code” and instead leave it to some unknown caller to make sense of the error. Which is a stretch.

            No. Returning a WP_Error means that every single consumer of your function (and possibly every sub-consumer thereafter) needs to be aware of that WP_Error and check for it. Something as simple as adding a filter to change some string might throw a fatal error, because your string happended to be a WP_Error.

            I would guess that errors because of acting on the wrong return value (be it WP_Error or something else) are among the most common errors across all WordPress themes and plugins.

            Also, regarding context, exceptions are just normal objects, so you can attach as much context as you need.

            IMO error handling should happen as close to the source of the error as possible because you know the most about the error at the source, not delegate it to some far away code that someone else might have written.

            According to that logic, the PHP file functions should not throw an error when a file is not accessible, but rather show some HTML message to the user and exit?

            But your example threw an exception even for a logic error, which even Betrand Meyer (OOSC) says should not be handled with exceptions. And he wrote the (initial) book on exception handling!

            I haven’t read that book, but if he states that logic errors should not throw exceptions, I strongly disagree.

            If the former I would question why calling a function that either generates the error message or redirects to a URL that says the DB is down is not the better solution? Why is a more complex architecture better when there are simple solutions to deal with things like a missing DB?

            Because the view should not know anything about redirections or databases. That is just spaghetti code.

            So using the database storage system being gone as a justification for using exceptions in WordPress is moot.

            No, it is not. That is how all of my database connections are set up. If the visitor submits a form, and the database to act upon as a result of that form is not available, I don’t want the visitor’s input to just be lost. Everything gets logged and an exception is thrown. The visitor is notified that there was a problem processing his request, the sys admin is notified that the DB is down, the developers are notified that there was a critical exception and the visitor’s input is stored to be able to re-process it manually later on.

            If the file system, I would argue that you won’t be running the code that would throw an exception anyway if you can’t access the file system where the code lives.

            You can’t just assume that the filesystem where the web server’s code runs on is the same than the one where the file that was currently requested is on.

            Yes you can deal with it. Either display an error view in the place of the view that says (something like) “Data is currently unavailable; see your webmaster for more details” or return a WP_Error object and let the code that calls it effectively display the same thing.

            Again, lots of assumptions you cannot just make as such:
            – The view doesn’t know where it will be rendered (it might be rendered into a PDF, into an email, …).
            – The view doesn’t know whether there is a webmaster or not (it might be a mobile app, a CLI tool, etc…).
            – The view does not know what format the output should be in (it might be HTML, plain text, etc…).

            You are only thinking in procedural code (which as I said renders exceptions rather useless). With OOP code, your view code will probably be in a different package, possibly written by a different author. All the view knows is what it should render, and whether it manages to do that successfully or not.

            I feel like what I am suggesting is equivalent to recommending unit testing. Yes writing unit tests can be tedious but writing them is how you create a robust system. Some things cannot be easily simplified.

            I don’t think that comparison works.

            I could just as easily say “Any reliable PHP system will handle errors as close to the source as they can” but me stating it does not make it any more or less authoritative than your statement.

            The intention was not to make it sound authoritative, but rather to specify what my assumptions are when I am writing code that uses exceptions. When someone uses my code and cannot properly deal with the exceptions it throws, then my code is a bad fit for that person.

            There are a set of guidelines that most web applications and frameworks adhere to, that have proved to be a good way to improve reliability and maintainability of these systems. Most include “not having error handling as an afterthought” and “logging all things”.

            Postel’s law applies here, aka the Robustness Principle:
            “Be conservative in what you do, be liberal in what you accept from others.”

            This applies to network protocols, not software architecture.

            Requiring others to follow your architecture and use exceptions when most in WordPress never do is not what I would call liberal in what you accept from others.

            I never cared much about what most others do. I have already stated at several occasions that I consider that “what most WordPress developers do” is not to be taken as an example.

            Well, that is an opinion. I see the error handling and say: “Ah, what a great programmer; they make sure to write robust code.”

            Robust code, in my opinion, is code that is easy to reason about and easy to maintain. Code that is made up of 80% error handling logic is neither.

            There is no reason you can’t have a top level error handler but also seek to handle every error that you can as close to the error source as possible. The top level error handler can be there just in case, not there to actually be used on purpose.

            I actually agree with that. I never said that you need to throw an exception on every single error condition. If you can deal with the error locally, it is not an exception, though.

            My point was that you ignored the errors where they occurred.

            And my further point is that the most appropriate point in the code to handle an error is (almost?) always as close to where the error occurred as possible.

            No, you misunderstood what I meant then. No error is ignored. Errors that can be handled locally are handled locally. Errors that cannot be handled locally are thrown as exceptions.

            And I would also intend to catch exceptions thrown by lazy programmers for plugins I am forced to use by clients where the lazy programmer decides to throw exceptions rather than handle error where they should by handled; close to the source (and yes that is a dig, but meant only in good humor. :-).

            Proud to be a lazy programmer then. Lazy programmers avoid redundant code and tend to forego short-term gains for long-term maintainability.

            And there is your other dig, you knowing how much I despise PHP’s interfaces. ¡Viva la Revolución!

            I prefer a proper design over flex-hack-ability.

            On a more general note: I do think that you shouldn’t use exceptions in your case, as your code seems deeply rooted in the procedural world (which is not a bad thing per se, but comes with a given set of limitations, just as OOP has a different set). They wouldn’t provide you with any benefits, so I understand your dislike.

            I don’t think further continuing our discussion here makes any sense, as we’re talking about different paradigms. Exceptions are mostly OOP-only, I cannot provide you with any valid arguments of why they would be great in procedural code, as there are none. My arguments are simply moot if you just transpose them into procedural code to refute.Report

        • "I don't differentiate between WordPress and non-WordPress. Developing with the PHP language should ideally be of equal quality everywhere."

          And on that we disagree, which is likely why we are so often at odd on these topics. Matter of fact one of my planned blog posts — in support of my 2017 New Year's resolution to start blogging again — is a post to be entitled "PHP best practices are NOT (always) WordPress Best Practices."

          IMO it is both unrealistic to ignore culture and majority skill level of a developer community when promoting best practices to that community. This is akin to promoting that school curriculum should he the same from pre-schoolers through PhD candidates.

          And IMO it is also irresponsible to promote complex "best practices" requiring significant architectural experience when a poorly-architected complex system is the worst of both worlds raising bug counts and reducing maintainability.

          BTW, I'm fine with you or anyone choosing to code with generally recognized PHP best practices for WordPress — I do myself in many cases — but I think promoting complex best practices for WordPress can be a disservice to the community at large since most will not know they don't have the experience to architect well (the Dunning-Kruger effect).

          "Specific implementations are easy to code, it is the reusable abstractions that take more experience to design correctly."

          And therein lies one of my biggest objections with pushing too much onto WordPress developers that do not yet have the experience to — or may not want to invest the time into being able to — design correctly. Poorly designed and abstracted OOP is often much worse than poorly designed yet literal procedural coding.

          "No. Returning a WPError means that every single consumer of your function (and possibly every sub-consumer thereafter) needs to be aware of that WPError and check for it."

          And I argue that it is a benefit that leads to more intentional coding.

          "Something as simple as adding a filter to change some string might throw a fatal error, because your string happended to be a WP_Error."

          By the same token if you throw an exception in the middle of (what should be implemented as a transaction, but never is in WordPress) you have done more harm than good. So for the most part once functions and methods I call start throwing exceptions I now need to wrap every bit of code I write in a try {...} catch {...} to make sure that an exception does not create unexpected condition that is hard to debug yet for which I should have handled.

          And I am assuming that the developer is not in control of all the code in the application, such as when using WordPress and plugins. Of course if you have the luxury of being the sole developer where you can write all code for the entire application, then sure, knock yourself out and exception away!

          "I would guess that errors because of acting on the wrong return value (be it WP_Error or something else) are among the most common errors across all WordPress themes and plugins."

          I definitely do not disagree with that, but exceptions just move the goal post elsewhere and make finding the source of the error harder. Better to have an error at the point of failure than in other code that does not point to the source of the error.

          "According to that logic, the PHP file functions should not throw an error when a file is not accessible, but rather show some HTML message to the user and exit?"

          trigger_error() is very different from throw new Exception(). The HTML pinpoints for the developer the exact location at which PHP could no longer continue. Throwing an except obscures the location at which PHP could no longer continue.

          "I haven't read that book, but if he states that logic errors should not throw exceptions, I strongly disagree."

          See, there is no objective authority that defines exactly what every best practice should be, it is all just difference of opinions, such as yours vs. mine. Though I daresay Betrand Meyer has a lot of adherents to his perspectives on the subject since he was the first to write widely about exceptions.

          In my opinion, logic errors should trigger a system failure to ensure that all such errors are eventually found and corrected. I caveat however for systems where failing would be catastrophic (medical equipment, vehicles including airplanes and spaceships, etc.) in which case logging and graceful recovery are preferable. But in those special cases there are almost certainly people paying attention to the error logs; not so for most WordPress websites.

          Joel on Software also concurs:

          "People have asked why I don’t like programming with exceptions. My policy is: 'Never throw an exception of my own. Always catch any possible exception that might be thrown by a library I’m using on the same line as it is thrown and deal with it immediately.'"

          Why?

          "1. They are invisible in the source code."

          "2. They create too many possible exit points."

          After which:

          "A better alternative is to have your functions return error values when things go wrong, and to deal with these explicitly, no matter how verbose it might be."

          Exactly what I am proposing. And he wrote that about C++ and Java which are not exactly procedural languages as you later imply my counter-examples to be.

          "Because the view should not know anything about redirections or databases. That is just spaghetti code."

          That is a false binary. If the view does not want to handle it then it can log the error and alternately package up its own WP_Error and return it to its caller.

          That said, moderation in all things. In WordPress and even PHP often purity results in a lot more complexity. While I agree from a purist perspective that the view should not redirect there is no real pragmatic reason that it should not redirect on failure.

          There is also an argument I subscribe to that is all code has many assumptions baked in to every line. To address every assumption on every line of code — exception or return value — would result in software requiring an infinite budget and that could never be completed. But most assumptions in good quality software fail so rarely that — assuming failure is not catastrophic — their failure should simply be logged then ignored.

          For example, WordPress checks the DB in a procedural call within wp-settings.php, and echos an error if the DB is unavailable and then dies. The likelihood of the DB becoming unavailable after that check and during the rest of the page load is rare, and the downside is often a page does not render completely. If that page is transferring money from one account to another, for example, then yes, we need to ensure the DB is there. Otherwise, it is most prudent to just log then ignore that type of potential error.

          "If the visitor submits a form, and the database to act upon as a result of that form is not available, I don't want the visitor's input to just be lost. Everything gets logged and an exception is thrown."

          If you or your client decide that is worth the cost to implement extra handling here for this rare case, then knock yourself out; it all depends on your business case. But not all use-cases are equally deserving of the cost of 99.999+% robustness.

          OTOH, logging such errors can easily be accomplished without exceptions.

          "You can't just assume that the filesystem where the web server's code runs on is the same than the one where the file that was currently requested is on."

          In WordPress, you can assume that 99.9% of the time. (I just made that statistic up.) And if not, you have the wrong hosting; move to a provider with a more standard infrastructure.

          BTW, my comment was about one PHP file calling another PHP file, not a PHP file resizing an image, for example. You are correct that a media file may be stored somewhere else besides a PHP file — in which case you can handle errors without exceptions — but having two PHP files on different file systems within a single WordPress app seems nonsensical to me.

          "You are only thinking in procedural code (which as I said renders exceptions rather useless)."

          I beg your pardon. I have been working with and teaching object oriented programming since the late 1980s. I am not thinking in "procedural code" and it is condescending for you to imply. Just because I do not agree with your perspective does not mean I am "only thinking in procedural code."

          "With OOP code, your view code will probably be in a different package, possibly written by a different author. All the view knows it what it should render, and whether it manages to do that successfully or not."

          Nothing I have said precludes using other people's code where the view either uses a logger I provide to record errors or uses a return values to indicate that a problem occurred.

          As a matter of fact I am advocating that other people's code not throw exceptions but instead allow me to handle thing they cannot handle then-and-there. Doing otherwise forces the user of the library to always deal with exceptions, which I think you have even said "should be exceptional."

          "When someone uses my code and cannot properly deal with the exceptions it throws, that my code is a bad fit for that person."

          On that we agree. :-)

          "There are a set of guidelines that most web applications and frameworks adhere to, that have proved to be a good way to improve reliability and maintainability of these systems."

          Appeal to authority?

          "Most include "not having error handling as an afterthought" and "logging all things"."

          These are orthogonal to the debate of return value vs. throwing exceptions.

          Having a standard of returning WP_Error as return values on error is not an afterthought, just as throwing an exception is not the only approach that indicates forethought.

          And logging all the things can just as easily be handled using WP_Error as when throwing exceptions, except for when calling other people's code who may not be logging errors in their own code that they do not surface by return value or exception.

          "This applies to network protocols, not software architecture."

          I love this essay written by Michael Feathers, author of the highly rated book "Working Effectively with Legacy Code" (emphasis mine):

          "The thing that I don’t think many people appreciate about Postel’s Law is its universality. In software, it’s not just about creating components for a network. You see Postel applied in command line utilities in Unix. Many of them are tolerant at input and very regular at output. This allows us to string them together with reasonable assurance that the composition will work. You can also see it at work in the HTML rendering engines of browsers. Browsers have historically been remarkably tolerant of ill-formed HTML and that allowed the web to grow tremendously fast."

          "…"

          "The galvanizing force behind Postel is the narrowing that happens between the input and the output. In physical terms it is a lessening in size but in information terms we can see it as an analog to lessening of bad variation. The world of information is chaotic. Errors creep in, but if every component takes the opportunity to make things a little simpler or cleaner, it acts as a counter-balance to those errors. In the aggregate, systems become more robust.

          Also this blog post (emphasis also mine):

          "In programming, this is called the robustness principle and reflects the idea that computer interfaces should be able to accept many different forms of information but always give you information in the same way. Then, just about anyone can send something in to the interface, but you always know what to expect coming back out.

          "…"

          This is a fantastic principle for developing software – your system is flexible, creating a shallow learning curve – but there’s also a specific standard for how it works. It’s always easier to use something when it “just works,” and even more so when it doesn’t ever surprise you at the end of the day."

          So in both their and my opinion the application of the Robustness Principle is far broader than just network protocols and directly applies to programming when working with other's code.

          "Robust code, in my opinion, is code that is easy to reason about and easy to maintain. Code that is made up of 80% error handling code is neither."

          I strongly agree with the former and strongly disagree with the latter. The latter can achieve the former through better use of control structures. (to be covered in a planned future blog post of mine.)

          "If you can deal with the error locally, it is not an exception, though."

          Which brings me to my core principle, rhetorically, is there ever an error locally that you cannot deal with?

          I assert there is no error you cannot handle locally as long as the PHP runtime systems does not bail on you in which case nothing we can debate here will matter. If the calling code throws an exception, catch it and return an error value. And for anything else, return an error value.

          If you catch or receive an returned error and you don't want to know anything about the error just log it and then return it to the caller but hopefully not before annotating it with your own context, such as what you were calling that failed.

          None of which requires exceptions.

          No, you misunderstood what I meant then. No error is ignored. Errors that can be handled locally are handled locally. Errors that cannot be handled locally are thrown as exceptions."

          Or maybe you misunderstood what I meant?

          Let me use an example. $foo->A() calls $bar->B() which calls $baz->C(). Only A() contains a try {...} catch {...} and only C() contains a throw. The error then passes from C() through B() directly back to A(). In that case B() "ignores" the error.

          But if that is not your definitions of "ignored" let's please not debate it because now we have an example that illustrates my reason for saying you ignored it; let's focus on the example instead.

          Or are you saying that every method and every function should contain a try {...} catch {...} so that exceptions thrown for errors are never ignored? If so, we might be having a different debate than I realized…

          "Proud to be a lazy programmer then. Lazy programmers avoid redundant code and tend to forego short-term gains for long-term maintainability."

          Well, there are good lazy programmers — as you describe — and bad lazy programmers, to commit a false binary. But in that spirit the latter write code that is irresponsible. And IMO throwing exceptions is usually irresponsible.

          "I prefer a proper design over flex-hack-ability."

          Just saying it is proper does not make it so, it only repeats academic group think.

          PHP's interfaces have pros and cons. I can see where see they are useful in a few contexts — do you not admit they are ever harmful? — but I think PHP's interface's cons outweigh their pros especially when used in the context of WordPress plugins and themes. Obviously you have a different opinion.

          BTW, ranting about the cons of PHP interfaces is another of my planned blog posts, although I want to make sure I write more useful how-tos rather than contrarian rants.

          "as your code seems deeply rooted in the procedural world"

          To be clear I find that assertion condescending. It does not make me mad at you (for some reason, though we often disagree, I do find you quite likable) but I would prefer you not make such assumptive statements simply because my view of best practice differs from yours.

          "I don't think further continuing our discussion here makes any sense, as we're talking about different paradigms."

          Sorry, and too late, I already wrote all the above before I read this.

          We can agree to disagree, which might be how you will want to reply? I doubt many people will read this far into our debate anyway

          "Exceptions are mostly OOP-only"

          Thus your argument seems to be that if I think throwing exceptions is bad then I must be using procedural code? I reject that assertion. Everything I have written about and proposed works fine in an OOP architecture, it is just not the type of OOP architecture you prefer.Report

          • Hi Mike,

            I don’t mean to interrupt the conversation you’re having with Alain – I’m finding it helpful seeing coding architecture discussed an analysed like this. But I had a few questions about your arguments:

            So for the most part once functions and methods I call start throwing exceptions I now need to wrap every bit of code I write in a try {…} catch {…}…

            If I’m using WP_Error I have to wrap any code I write in if ( is_wp_error( $return_value ) ) { ... } else { ... }. To me it appears nothing is gained in using WP_Error, so what advantage is there in using it? Perhaps parity was your point here, but you go on to say:

            …to make sure that an exception does not create unexpected condition that is hard to debug yet for which I should have handled.

            How so difficult? An uncaught exception will be recorded in your error logs – and, most importantly, a trace to point it was thrown. An unhandled error value on the other hand might cause a fatal error (in which case the actual error recorded is that you are using WP_Error when you expected something else). It’s not necessarily easy to determine where that WP_Error object originated from (which is why I think Alain brought up the example of a filter returning one). Or your application will continue as if nothing bad has happened. This might be benign, or it may cause some odd behaviour for which it’s difficult to pin down the original cause.

            You quote two points by Joel. (2) seems odd, because it doesn’t create any more exit points than returning an error object. (1) is a valid point in PHP (but oddly not in Java which Joel is talking about, where you would get a compile error for not catching or declaring an exception).

            As for (1), ok, I see your point. It’s not explicit when reading code that a called function might throw an exception, unless you’ve put it in a try statement or it is documented (though clearly written code is always the best documentation).

            My impression from your discussions was that your point is that errors should be handled immediately, so you need to wrap everything in a try statement. An d in which case you may as well use an error object. I would turn that on its head an ask why use an error object when you can use an exception? It’s easier to debug an exception that wasn’t immediately handled (or handled at all) than a missed error object.

            And while I agree that developers should be ensuring nothing slips through the net, and automated tests should be demonstrate that – we shouldn’t seek to punish developers with obscure error messages when they slip up. Incidentally it’s much easier to implement a “fail safe” for exceptions than error objects.Report

Leave a Reply

Your email address will not be published. Required fields are marked *