Exception Best Practices in PHP 5.3

September 15th, 2010 § 23 comments

Every new feature added to the PHP runtime creates an exponential number of ways developers can use and abuse that new feature-set. However, it’s not until developers have had that chance that some agreed-upon good usage and bad usage cases start to emerge. Once they do emerge, we can finally start to classify them as best or worst practices.

Exception handling in PHP is not a new feature by any stretch. In this article, we’ll discuss two new features in PHP 5.3 based around exceptions. The first is nested exceptions and the second is a new set of exception types offered by the SPL extension (which is now a core extension of the PHP runtime). Both of these new features have found their way into the book of best best practices and deserve to be examined in detail.

Special note: some of these features have existed in PHP < 5.3 or are at least capable of being implemented in PHP < 5.3. When this article mentions PHP 5.3, it is not in the strictest sense of the PHP runtime. Instead, it is meant that code bases and projects that are adopting PHP 5.3 as a minimum version but also all of the best practices that have emerged in this new phase of development. This phase of development highlighted by the “2.0″ efforts of projects like Zend Framework, Symfony, Doctrine and PEAR to name a select few.

Background

Previously in PHP 5.2, there was a single exception class Exception. Generally, speaking from a Zend Framework / PEAR coding standard perspective, this exception class became the root for all exceptions that might be thrown from within your library. For example, if you created a library for your company MyCompany, then you would, according to ZF/PEAR standards, have prefixed all code with MyCompany_. For this library, you might create a base exception for your library code: MyCompany_Exception, which extends the PHP class Exception and from which all your components might inherit, subclass, and throw. So, if you created a component MyCompany_Foo, it might have a base exception class called MyCompany_Foo_Exception that is expected to be thrown from within the MyCompany_Foo component. These exceptions can be caught by attempting to catch MyCompany_Foo_Exception, MyCompany_Exception, or simply Exception. This would allow 3 levels of granularity (or more depending on how many times the MyCompany_Foo_Exception was subclassed) to consumers of this component in this particular library, and handle that exception in a way they deem fit.

New Feature: Nesting

In PHP 5.3, the base exception class now handles nesting. What is nesting? Nesting is the ability to catch a particular exception, create a new exception object to be thrown with a reference to the original exception. This then allows the caller access to both the exception thrown from within the consumed library of the more well known type, but also access to the exception that originated this exceptional behavior as well.

Why is this useful? Typically, this is most useful in code that consumes other code that throws exceptions of its own type. This might be code that utilizes the adapter pattern to wrap 3rd party code to deliver some kind of adaptable functionality, or simply code that utilizes some exception throwing PHP extension.

For example, in the component Zend_Db, it uses the adapter pattern to wrap specific PHP extensions in order to create a database abstraction layer. In one adapter, Zend_Db wraps PDO, and PDO throws its own exception PDOException, Zend_Db needs to catch these PDO specific exceptions and re-throw them as the expected and known type of Zend_Db_Exception. This gives developers the assurance that Zend_Db will always throw exceptions of type Zend_Db_Exception (so it can be caught), but they will also have access to the original PDOException that was thrown in case it is needed.

The following is an example of how a fictitious database adapter might implement nested exceptions:

To utilize a nested exception, you would call the getPrevious() method of the caught exception:

Most recent PHP extensions have OO interfaces. As such, those API’s tend to lean on throwing exceptions instead of raising errors. A short list of exception throwing extensions in PHP include PDO, DOM, Mysqli, Phar, Soap and SQLite.

New Feature: New Core Exception Types

Also in PHP 5.3 development we are shining a light on some new and interesting Exception types. These exceptions have been in place since the PHP 5.2.x, but it has not been till recently and the “re-evaluation” exception best practices that they are now gaining some limelight. They are implemented in the SPL extension and are listed on the manual pages located here. Since these new exception types are part of core PHP as part of SPL, they can be used by anyone who targets PHP 5.3 as the minimum runtime for their code. While this might seem less important for when writing application layer code, the way we adopt and use these new exception types becomes even more important when we are writing and consuming library code.

So why new exception types in general? Previously, developers attempted to give more meaning to their exceptions by putting more information into the message of the exception. While this is good, it has a few drawbacks. One is that you cannot catch an exception based on a message. This can be a problem if you know a set of code is throwing the same exception type with various message for various exceptional conditions that can be handled differently. For example, an authentication class that during $auth->authenticate(); it throws the same type of exception (let’s assume Exception), but with different messages for two specific failures: a failure where the authentication server cannot be reached and the same exception type but different message for a failed authentication attempt. In this case (nevermind that using Exceptions might not be the best way to handle authentication responses), it would require string parsing the message to handle those two scenarios differently.

The solution to this is clearly some way to codify exceptions so that they can be easily interrogated when trying to discern how to react to this exceptional situation. The first response libraries have had is to use the $code property of the Exception base class. The other is to create multiple types, or new exception classes, that can be thrown to describe the behavior. Both of these approaches have the same simple drawback. Neither has emerged as a best practice and as such, neither is considered a standard, thus each project attempting to replicate this solution might do so with small variations that force the consumer to go back to the documentation to understand the library specific solution that was created. Now with the new types approach in the SPL, otherwise known as the Standard PHP Library; developers can utilize these new types in the same way in their projects and the projects they are consuming since a best practice for these new types has emerged.

The second drawback of the detailed message approach is that it makes understanding the exceptional situation harder for non-english or limited-english speaking developers. This might slow down some developers when trying to decipher what an exception message is trying to convey. As many developers as there are writing exceptions, there are equally as many variations in how they will describe that situation in the message since there is no standard for conformity or for codification.

So How Do I Use Them, Give Me The Dirty Details?

There are a total of 13 new exceptions in the SPL. Two of them can be considered “base” types: LogicException and RuntimeException; both extend the PHP Exception class. The remainder of the methods can thusly be broken down into three logical groups: the dynamic call group, the logic group and the runtime group.

The dynamic call group contains the exceptions BadFunctionCallException and BadMethodCallException. BadMethodCallException is a subclass of BadFunctionCallException which in turn is a subclass of LogicException. That means that these exceptions can be caught by either their direct type, LogicException, or simply Exception. When do you use these? Generally, these should be used when an exceptional situation arises as a result of an unresolvable __call() during a method or when a callback cannot find a valid function to call (or better put, when something is not is_callable()).

For example:

While the direct example is inside __call and anywhere near something that will call_user_func(), this group of exceptions are also useful when developing any kind of API where dynamic method call and function call lookups are utilized. An example of this would be a SOAP or XML-RPC client/server who is capable of issuing and/or interpreting method requests.

The second group is the logic group. This group consists of DomainException, InvalidArgumentException, LengthException, and OutOfRangeException. These exceptions are a subclass of LogicException which is in turn a subclass of the PHP Exception class. You use these exceptions when there is an exceptional situation that arises from either a mutation of state or as a result of bad method or function parameters. To get a better understanding of this, we will first look at the last group of exceptions.

The final group is the runtime group. It consists of OutOfBoundsException, OverflowException, RangeException, UnderflowException, and UnexpectedValueException. These exceptions are a subclass of RuntimeException which is in turn a subclass of the PHP Exception class. These exception should be used when an exceptional situation arises during the “runtime” of a function or method call.

How do these logic group and runtime group work together? If you look at the anatomy of an object, one of two things is generally happening. First, the object will be tracking and mutating state. This means the object is generally not doing anything (yet); it might have configuration passed to it; it might be setting up properties (via setters and getters); or, it might be getting references to other objects. Second, when the object is not tracking and mutating state, it is operating – doing what it was designed to do. This is the object’s runtime. For instance, during the objects lifetime, it might be created, passed a configure object, then it might have setFoo($foo), setBar($bar) called. During these times any kind of LogicException should be raised. In addition, when the object is asked to do something, with parameters, for example $object->doSomething($someVariation); during the first few lines when it interrogates that $someVariation variable, it would throw a LogicException. After it is done interrogating $someVariation, and it goes on about doing its job of doSomething(), this is considered its “runtime” and in this code it would throw RuntimeExcpetions.

To better understand, we’ll look at this concept in code:

Now that this concept is understood, what does this do for a consumer of this code base? The caller can be sure that anytime they are mutating the state of an object, they can catch exceptions with the most specific type, for example InvalidArgumentException or LengthException, and at least LogicException. By having this level of granularity, and multiple types involved, they can catch the exception minimally with LogicException, but also get greater understanding of what when wrong via the actual type of the exception. This same concept applies for the Runtime group of exceptions as well, more specific types can be thrown and either the specific or the less specific type will be caught. This offers a greater deal of knowledge about the situation and granularity of control to the caller.

Below is a table of the information you might find of interest concerning these SPL exceptions

Best Practices In Library Code

Since the advent of these new exception types in PHP 5.3, a new best practice for library code has also emerged. While it is most beneficial to get a standard specialized exception type like InvalidArgumentException or RuntimeException, it would also be useful to catch component level exceptions. You can read a more in-depth discussion of the concepts on the ZF2 wiki or the PEAR2 wiki.

The long and short of this, in addition to the best practices listed above, is that there should be a component level type that can be caught for any exception that emanates. This is accomplished by using what is known as a Marker Interface. By creating a component level marker interface, real exception types inside a given component can extends the SPL exception types and be caught by any number of class types at runtime. Let’s examine the following code:

Assuming the above code, if one were to execute MyCompany\Component\Component::doSomething(), the exception that is emitted from the doSomething() method can be caught by any of the following types: PHP’s Exception, SPL’s UnexpectedValueException, SPL’s RuntimeException the component’s MyCompany\Component\UnexpectedValueException, or the component’s MyCompany\Component\Exception. This affords the caller any number of opportunities to catch an exception that emanates from a given component within your library. Furthermore, by analyzing the types that make up the exception, more semantic meaning can be given to the exceptional situation that just occurred.

Summary

In summary, this article should help guide you in creating and throwing more meaningful exceptions in a standards based and best practices way by negating the emphasis of the exception message and putting more emphasis on the exception type. If you’d like to carry on the discussion of these concepts feel free to comment here, on the PHP documentation pages, or in the ZF2 wiki comments section for the Exception proposal linked above.

Tagged , , , ,

  • Anil

    Thanks.. Awesome article

  • http://epixa.com Court

    Fantastic article. I’ve been using SPL exceptions for awhile now, but I’ll admit that I sometimes confuse the use of logic and runtime exceptions. Hopefully this will help me clear up what I previously considered to be a gray area.

  • Pingback: Exceptions and the handling thereof… | Debuggery

  • http://saltybeagle.com/ Brett Bieber

    I really think this is a good direction to go by eliminating the base Zend_Exception class dependency, still allowing per-component catch flexibility, and supporting the descriptive SPL Exception base classes. Excellent write-up on this Ralph. Thanks

  • Daniel A, Tiecher

    Congratulations on your post. Really high quality and informative content.

    The bad thing is that only a small portion of the PHP community is following these kinds of advancements in the way we right code in PHP…

    Anyhow, thanks for taking the time to write it!

  • http://www.davidkmuir.com David

    Really good writeup! I’ve been looking for more detailed info on the use these exceptions for years. Now I know what each group of exceptions are for, but would love an in-depth description on the usage of the individual exception types. Are there any good articles available on that?

  • Ramon Henrique Ornelas

    Congratulations great article.

  • http://artur.ejsmont.org/blog/ Artur Ejsmont

    Hi there, nice writeup.

    I have read some time ago about marker interfaces for exceptions and i love it. Its too late for our internal apps but i will be using it for sure.

    As to exceptions in constructor, i cant remember exactly but i think it was in 5.2. I used to have problems in constructors and exception would not be thrown out of them … cant rememeber details.

    Is it guaranteed now that throwing LogicException in constructor would always work properly? or will it just return null instance or something stupid like that?

    Thanks for a nice article

  • http://blog.nickbelhomme.com NickBelhomme

    Awesome writeup on Exceptions. It really makes things clear on how and when to use the SPL exceptions. Great job Ralph (as always).

  • Pingback: Revue de presse Industrialisation PHP des semaines 32 à 38 (2010) | Industrialisation PHP

  • Dmitri

    “… list of exception throwing extensions in PHP …”. Nice article.

  • http://johnny@johnnypeck.com Johnny Peck

    Great article Ralph. Thank you for taking the time to write it up. The new exception types really do clarify how to implement clear and concise exceptions. Considering the sparse descriptions/documentation in php.net manual regarding each exception, your contribution in the this article really does the community a great service. I could see this information becoming a great conference talk! Aloha.

  • http://websitecenter.ca Montreal Web Design

    Don’t go overboard with new exception, create new exceptions only if you can recover from them.

  • Emilio Navarro

    Exceptions become crystal clear after this article. Great work Ralph!

  • Pingback: Exceptions and the handling thereof… « Debuggery

  • Pingback: PHP Exceptions – How to use exceptions properly? « The way I see it

  • Matthew Bonner

    I’m not being funny but if I written an article saying you should use exceptions in a particular way this doesn’t mean I’m right.

    I don’t think this is a time or place to discuss exceptions, but I would like to give my two cents on how to use exceptions.

    I actually disagree with throwing logic exceptions based on what you have mentioned on the basis of how other languages use exceptions. I’m also going to disagree on the matter of “create new exceptions only if you can recover from them.” I think some exceptions are not recoverable, and I think there should be as a minimum a specific set of exceptions you define yourself, including (but not limited to):
    MissingArgumentException // when you expect an argument that isn’t passed (PHP handles this unless you use func_get_args()
    ArgumentException // when an argument passed is invalid (use this when you can’t use type hinting)
    SecurityException // when you detect a security issue such as an attack

    So let me just go back to whether you should be throwing a logic exception or not, here is what I think.

    If you are setting a property to a numeric value which can’t be negative, throw an OutOfRangeException, not a LogicException.

    If you are setting a property which isn’t allowed to be a particular value, such as NULL, then throw a UnexpectedValueException exception.

    If you have your own file class, and you can’t open a file for reading (as an example), then throw an IOException (of course you will have to define this exception yourself).

    So don’t just throw a logic exception because this article tells you to, in fact, I would completely ignore this article and look at how other languages have successfully used exceptions.

  • http://ralphschindler.com/ Ralph Schindler

    @Matthew Bonner: OutOfRangException is a LogicException:

    Object of class [ class OutOfRangeException extends LogicException ] { … }

    When the article talks about throwing LogicException, it means the family of LogicExceptions (InvalidArgument, OutOfRange, Domain, Length) … not the base type LogicException.

    “If you are setting a property which isn’t allowed to be a particular value, such as NULL, then throw a UnexpectedValueException exception.”

    Thats not really correct. UnexpectedValueException is for when a method is running and finds an unexpected value, or in other words, for an value which was not presented to a method as an argument. This is evident in that UnexpectedValueException extends RuntimeException.

  • Matthew Bonner

    From Microsoft’s .NET source code (I got permission to extract this comment):
    // The ArgumentException is thrown when an argument does not meet
    // the contract of the method. Ideally it should give a meaningful error
    // message describing what was wrong and which parameter is incorrect.

    More specifically, “which parameter is incorrect.”

    ArgumentException is the .NET equivalent of the PHP InvalidArgumentException, Java uses IllegalArgumentException. Funny enough, the comment in the Java reference says “Thrown to indicate that a method has been passed an illegal or inappropriate argument.”

    My point being, if you pass a NULL argument, either create an ArgumentNullException exception which extends the UnexpectedValueException exception, or throw an UnexpectedValueException exception.

    I can’t see any grounds for why you would disagree, either you misunderstand what each exception should be used for, or PHP is the exception, and I don’t think it is the latter.

  • http://ralphschindler.com/ Ralph Schindler

    Let me try to put it another way. The purpose of UnexpectedValueException is when a method encounters a variable who’s value or type is unexpected in cases where that variable *was not* an argument in the immediate scope. If the source of the value was an argument in the immediate scope, then InvalidArgumentException is what you want to use. If you want to fully understand the whole context of a particular exception, you really need to look at the exceptions parent types. In this case, UnexpectedValueException extends RuntimeException, not logic exception.

    If you’re going to extend anything for the purposes of throwing an argument exception, you’d be better served by extending InvalidArugmentException.

    Perhaps the wording is so close as to illicit your confusion, but ultimately that (and the best practices decided on by the community by-and-large) is why this article was written.

    That said, use what you think makes most sense. If people are using exceptions in their OO PHP code, that is win enough for me :)

  • Christian Weiss

    Standards are fine and elate team mates to respect standards.

    SPL in general is good stuff – and SPL exceptions is a good idea, but due to missing examples, missing explanations on php.net and its ambiguity there is little acceptance in the PHP community and each exception is used with a different understanding in its meaning, depending on which developer is using it. Now after some years there is still no big adaptation of SPL exceptions in the PHP community.

    These issues are the reason why i elate team mates to write own exception classes. I know they are able to practice “clean code” – strongly believe they do not introduce ambiguity (better than SPL).

    Next issue i want to outline is: exceptions are part of your API.
    So use doc blocks to your methods and add @throws annotations for each exception thrown. When your method uses external code (other objects, external libs) the external exceptions would bubble through your method. External exceptions become part of your API this way. Every change to the external code (rename of an exception or introduction of a new exception) would require you to update your doc block, too. It is not a good idea to add these external exceptions to your API (to your doc block with additional @throws lines). If your method can not recover this exception it should re-throw it as your own exception at least. Do not forget to add a catch-all statement (PHP base exception) and re-throw your own exception . When doing this you are immune for external changes – you follow the open-closed principle. If your app is for PHP >=5.3 use nested exceptions when re-throw an exception.

    Your argument, that standardized exceptions would enable you to switch from one lib to another – i can not follow.
    To be able to switch from one lib to another lib without changing my code requires the following:
    a) two libs that implements the same interfaces
    b) two libs that offers same external behavior
    c) two libs that throws the same exceptions within the same event

    There is no kind of “interfaces with exceptions declaration” in PHP that can be used to keep a consistent API.
    SPL is trying to solve this by convention – but you can not solve this by convention, because you can imagine an infinity amount of problem domains – and good exception names that fits to that problem domain are available in infinity amount, too.

    Do not misunderstand me: i elate my team mates to follow conventions. There are a lot of conventions that do make sense. E.g. getter and setter methods which names are prefixed with “get” and “set”. Factory methods that are postfixed with “Factory”, etc. But trying to provide a convention (lib) with e.g. 200 getter names will never be enough. If there is a need for a naming convention then contribute this to a wide-used coding standard.

    PHP do need a kind of “interfaces with exceptions declaration” to define the “full” API.

    The only point that should be discussed in further detail is: Does it make sense to promote to categorize your exceptions into “runtime exception” or “logical exception”? I do not have a standpoint for that today, but i will think about it. But again, i do not see a reason why this should be introduced by a lib. Promote coding standards or best practices for that, would be a better way of doing that.

    Another point i want to propagate: do not use exceptions with exception-codes. Codes requires mental mapping which is bad style / old school (see “clean code” for details).

  • Pingback: Using Interfaces For Exceptions | BrandonSavage.net

  • Carsten Witt

    Clarifying article, Ralph. Thank you for this! Just for further clarification: You differentiare between using the Logic ones during object instantiation and configuration, and the Runtime ones during business. Did I get it right, to put in a nutshell:

    The “dynamic call group” is for everything concerning “calling” methods and functions; the “logic group” is useful for problems inside the parameter list; and the “runtime group” is for everything happening inside the method/function body?

What's this?

You are currently reading Exception Best Practices in PHP 5.3 at Ralph Schindler.

meta