PHP Exception Handling - ErrorException

PHP Exception Handling – DOMException

Next up in our in-depth PHP Exception Handling series, today we’re digging into the PHP DOMException error. There are a variety of reasons a DOMException can occur, but all of them are related to using the Document Object Model namespace and its powerful functionality.

In this article we’ll examine the DOMException in more detail, including where it sits in the PHP Exception Hierarchy, and how DOMExceptions might be commonly thrown using some functional sample code, so let’s get to it!

The Technical Rundown

  • All PHP errors implement the Throwable interface, or are extended from another inherited class therein.
  • Exception implements the Throwable interface.
  • DOMException extends the Exception class.

When Should You Use It?

Let’s jump right into it by looking at the full working code sample we have, which features two kinds of DOMExceptions that might typically occur. Following the sample below, we’ll break the code down in more detail to see exactly what’s going on:

Our first goal is to create a new DOMDocument instance, and append a new DOMElement instance to it. To that end, we have two similar methods, appendElementToDocument(DOMElement, DOMDocument) and appendElementByNameToDocument(string, DOMDocument):

These methods are comparable, except one expects an actual DOMElement instance to be passed as an argument, while the other uses a passed string $name to create said element. Either way, the element is then appended to the passed DOMDocument using the appendChild() method. If successful, we output a message, and if it fails, we throw (and catch) the exception.

To test these methods out we have just a few lines of code. We start by creating a new DOMDocument instance, then call appendElementToDocument(DOMElement, DOMDocument) with a new element named books:

This works just as expected and the output confirms the result:

Now let’s try the appendElementByNameToDocument(string, DOMDocument) method to create a DOMElement with the name of a dollar sign ($):

As it happens, the $ symbol is not a valid character within a DOM element name, so a DOMException is thrown, indicating as much in the message:

Our second test involves appending DOMElements to DOMDocuments again, but this time we’re trying something new: First, we append an element to a document, then we try to append that same element to a different document. This is performed in the crossDocumentAppendTest() method:

Everything works just fine until we get to the third appendElementToDocument(DOMElement, DOMDocument) call, which attempts to crossover the append action by appending $elementA to $documentB, even though $elementA is already appended to $documentA. As you can probably guess, this also results in a DOMException being thrown, this time indicating that we are manipulating the wrong document (referring to $documentB, in this case):

We solve this issue within the crossDocumentAppendTestSuccess() method:

As you may have noticed, the appendElementToDocument(DOMElement, DOMDocument) method returns a DOMNode or null object, which we’ve specified using the : ?DOMNode syntax at the end of the method declaration. This is a new feature introduced in PHP 7.1+, which makes it easy for us to use the result of that method call for further logic. Thus, in crossDocumentAppendTestSuccess() we assign the appendElementToDocument(DOMElement, DOMDocument) result to a $node variable and check if it exists or was null). In the event that no DOMNode instance was returned, that indicates our original append attempt failed (just as in the previous method), so we can perform one little trick necessary to get this crossover append to work.

The solution is to call the importNode(DOMNode) method on the DOMDocument instance that is to receive the new appendage. This imports the node into the document tree, behind the scenes, and returns the resulting DOMNode instance, which we’ve assigned to $importedNode. From there, it’s just a matter of calling the appendElementToDocument(DOMElement, DOMDocument) method one last time, but now we pass the $importedNode instance to $documentB, instead of the original $elementA version.

Our log shows this works just as expected, and the ultimate result is the same, but without throwing an unnecessary DOMException:

Check out the Airbrake-PHP library, designed to quickly and easily integrate into any PHP project, giving you and your team access to real-time error monitoring and reporting throughout your application’s entire life cycle. With automatic, instantaneous error and exception notifications at your fingertips, you’ll be constantly aware of your application’s health, including any issues that may arise. Best of all, with Airbrake’s robust web dashboard cataloging every error that occurs, you and your team can immediately dive into the exact details of what went wrong, making it easy to quickly recognize and resolve problems.