Jeff Carouth

Web and mobile developer. Agile apprentice.

Excepting With the SPL

| Comments

In my opinion  proper use of error handling within an application is the mark of seasoned, professional developer. It is far too often that I see code that explodes on every error or, even worse, does not consider that errors will occur during runtime.

One area that I like to make use of exceptions is unexpected input, especiallyin terms of function/method arguments. A lot of times the standard practice seems to be to return FALSE for invalid input, but the boolean value false should be reserved for boolean indication. Likewise, NULL should have a special connotation, semantically speaking.

In this first example, a repository (or mapper) is attempting to find a user with an id—let’s assume it is a database id—that should be an integer. (This code uses the Zend_Db_Table component to abstract queries, etc.)

[code language=“php”]class UserRepository implements IRepository { public function fetchById($id) { $data = $this->getDbTable() ->find($id) ->current();

if (null === $data) { return null; }

return new User($data->toArray()); } }[/code]

Notice there is no validation performed on the $id parameter which is pushed directly into the database table query. Granted the Zend_Db component will handle this error with minimal pain, i.e., you should be fairly protected against a SQL injection attack, but you know that your database table uses an integer for the ID column thus your application should only respond positively to an  integer value for $id.

[code language=“php”]public function fetchById($id) { if (!is_int($id)) { return false; } //…snip }[/code]

My first attempt (above) at validation uses the native is_int() validation function to check if the value supplied for $id is an integer. If it is not the function returns false. There is plenty of precedent behind using the value FALSE as the error state, but it is blatantly not semantic. FALSE is obviously not the user object I asked for, but it does not indicate what went wrong.

Finally, I decide to use the Zend_Validate component—for this trivial example it may be overkill, but it does the job nonetheless—to validate my input parameter for the user’s ID property. Also notice that I am now throwing an exception object, specifically an InvalidArgumentException.

[code language=“php”]public function fetchById($id) { $validator = new Zend_Validate_Int(); if (!$validator->isValid($id)) { throw new InvalidArgumentException( ‘User ID must be an integer. ); } //…snip }[/code]

The InvalidArgumentException exception is one of many defined in the SPL as an extension of a logic exception. The reason for using such an exception class would be to improve the readability and usefulness of client code. When I use the UserRepository object, my client code will look as follows. When an invalid argument, i.e., a non integer is given to the fetchById() method it is obvious which code path will execute.

[code language=“php”]try { $repository = new UserRepository(); $user = $repository->fetchById(“jcarouth”); } catch(InvalidArgumentException $e) { //we passed an invalid argument, i.e., a non-integer } catch(Exception $e) { //some other }[/code]

*[SPL]: Standard PHP Library