Exception Handling In PHP5 – Good Cop, Bad Cop

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, January 17, 2009

Follow me on Twitter as @mattiasgeniar

Exception handling. The “I’m so good, I don’t produce errors"-mentality can’t even save you from them. It’s bound to happen – either your code fails, or external libraries you’ve grown to accept produce faults outside of your control.

You need’m handled, it’s that simple.

And PHP offers you a couple of methods to “handle” errors, or warnings, generated by your PHP code. From basic Error Suppresion, to proper Exception Handling.

Take the following little example.

$db = mysql_connect($hostname, $username, $password);

The code above is one of the most common function calls in any website. Establish your database connection (in this case, to a MySQL server). While simple in theory, a lot can go wrong; MySQL server not running on that particular host, incorrect username/password, … You just don’t know how it’ll be handled.

You could expand it, to do the following.

$db = mysql_connect($hostname, $username, $password) or die (mysql_error());

Should anything go wrong, you’ll immediately show the corresponding MySQL error message. While this may be good for you – now you have the necessary information to debug – your visitor, who couldn’t even spell MySQL if the life of his newborn puppy depended on it, would just be annoyed.

Thus, we suppress the message. We don’t show the error message, we hide it. PHP’s Error Suppression is done using the @-sign, in front of your function call.

$db = @mysql_connect($hostname, $username, $password);

We may have hidden our error messages, we still haven’t handled them. We just prevented them from showing up.So how do we know the connection was established correctly? By checking the return type!

$db = @mysql_connect($hostname, $username, $password);

if (!$db) {
	echo "Connection failed.";
}

This will allow us to display a proper (and more importantly; a self-chosen and self-handled) error message to our visitor, instead of a message defined by MySQL which would just be jibberish to most.

When you want to disable your error message entirely, you can use the following code on top of your page. It will override any setting defined in the php.ini, all code behind this function call will have its errors/warnings/notices removed.

error_reporting(0);  // Disable all error reporting

You should note that, despite not showing any notice, warning or error message, script execution will stop when it reaches a fatal error message – and you won’t be notified of the error. The page will simply come to a halt, without a clue as to what happened, and where.

But there are occasions when there’s more need of handling an “Exception”, than of handling an Error. That’s why there is some advanced Exception Handling available to you in PHP5.

Let’s say you have the following base class “Person”, that has a method “Talk” to say a line of text “Hello World!".

class Person {
	function Talk ($message) {
		echo $message;
	}
}

$john_doe = new Person();
$john_doe->Talk("Hello World!");

If the $message should be empty – nothing would be shown. Thus, we need to handle the “Exception” of an empty string.

class Person {
	function Talk ($message) {
		if (!is_string($message) || strlen($message) == 0) {
			throw new Exception("People can't say empty sentences.");
		}

		echo $message;
	}
}

$john_doe = new Person();
try {
	// Attempt to say an empty sentence
	$john_doe->Talk("");
} catch (Exception $e) {
	// If the above fails, handle the exception
	echo $e->getMessage();
}

Notice how the method Talk() and its execution changed. There’s now a check in place, to see if the parameter is actually a string, and if it’s empty or not. If either of these checks fail, a new Exception will be thrown.

By placing the call of the Talk() method in a Try-Catch bracket, we can completely handle whatever exception message is thrown inside the method. If the Talk() does not go as planned, we can display the Exception message defined within the class.

This can be implemented further, by extending the base class Exception, and writing your own version of it – to do exactly what you want. Take a look at the code below.

// Extend the class "Exception" with our own Exception-class
class PersonTalkException extends Exception {
    function __construct($message) {
		LoggingClass::logEvent($message);

		MailerClass::mailAdministrator($message);
    }

    public function showStacktrace() {
    	// Show a stacktrace of this error
    	echo parent::getTrace();	// Method defined in the "Exception" base class
    }

}	

// Our base class "Person"
class Person {
	function Talk ($message) {
		if (!is_string($message) || strlen($message) == 0) {
			throw new PersonTalkException("People can't say empty sentences.");
		}

		echo $message;
	}
}

// Our script execution
$john_doe = new Person();
try {
	// Attempt to talk an empty sentence
	$john_doe->Talk("");
} catch (PersonTalkException $e) {
	// If the above fails, handle the exception within the PersonTalkException class
	// And then display the error message, defined within the Person class
	echo $e->getMessage();
	// And if requested, show a complete stacktrace of this message
	$e->showStacktrace();
} catch (Exception $e) {
	// If it's not an Exception of type PersonTalkException, display the generic one
	echo $e->getMessage();
}

This will create a new class “PersonTalkException” that extends the base functionality of “Exception”. It allows any exception that is thrown into this class, to be handled for this specific occasion. We can log the message, or mail it – depending on the situation.

The Try-Catch block has also expanded. At first, we see if we can catch an Exception with the type “PersonTalkException”. If the type matches, we display some specific items defined within this class.

If it’s not of the type “PersonTalkException”, just display the generic Exception message, without extras.

The Exception Handling should allow you to create more robust PHP applications, that won’t throw quite as many error messages. Mastering Exceptions also allows you to create simpler looking, more organized applications. No more nesting of if‘s until infinity, but simply throw an Exception, and continue on with your code.

class Person {
	function Talk ($message) {
		if (!is_string($message)) {
			throw new PersonTalkException("That's not a string!");
		}

		if (strlen($message) == 0) {
			throw new PersonTalkException("It's a string, but it's empty!");
		}

		echo $message;
	}
}

Keep your code clean, and make it easier for you to maintain endlessly large projects.

You can also define your own Error Handler Function (instead of just Exceptions, as shown above), by using the set_error_handler() function. This allows you to “catch” any error that might occur – including the ones not handled by Exceptions.



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.