4.3 Throwing and Catching Exceptions

PHP 5 has introduced an exception model that allows objects to be thrown and caught using the throw and try...catch statements.

The throw and try...catch statements provide a way of jumping to error handling code in exceptional circumstances: rather than terminating a script with a fatal error, exceptions are thrown, and can be caught and processed. The throw statement is always used in conjunction with the try...catch statement, and the following fragment shows the basic structure:

$total = 100;

$n = 5;



$result;



try

{

    // Check the value of $n before we use it

    if ($n == 0)

        throw new Exception("Can't set n to zero.");



    // Calculate an average

    $result = $total / $n;

}

catch (Exception $x)

{

    print "There was an error: {$x->getMessage( )};

}

The block of statements contained in the braces that follow the try keyword are executed normally as part of the script; the braces are required, even for a single statement. If a throw statement is called in the try block, then the statements contained in the braces that follow the catch keyword are executed. The throw statement throws an object and the catch block of code catches the thrown object, assigning it to the variable specified.

The catch statement specifies the type of object that is caught by placing the class name before the variable: the following fragment catches Exception objects and assigns them to the variable $x:

catch (Exception $x)

{

    print "There was an error: {$x->getMessage( )};

}

Specifying the type of object that is caught in the catch block is an example of a class type hint . We discuss class type hints in Chapter 14.

4.3.1 The Exception Class

While objects of any class can be thrown, PHP5 predefines the Exception class that has useful features suitable for exception reporting.

Exception objects are constructed with a message and an optional integer error code. The message and error code are retrieved using the getMessage( ) and getCode( ) member functions. The line number and filename of the script that creates an Exception object is also recorded and retrieved with the getLine( ) and getFile( ) member functions. These functions are used in Example 4-10 to define the formatException( ) function that returns a simple error message for a given Exception object $e.

Example 4-10. Simple try-catch
<?php



function formatException(Exception $e)

{

    return "Error {$e->getCode( )}: {$e->getMessage( )}

        (line: {$e->getline( )} of {$e->getfile( )})";

}





function average($total, $n)

{

    if ($n == 0)

        throw new Exception("Number of items = 0", 1001);



    return $total / $n;

}





// Script that uses the average( ) function

try

{

    $a = average(100, 0);

    print "Average = {$a}";

}

catch (Exception $error)

{

    print formatException($error);

}



?>

Example 4-10 shows how a try...catch statement is used to catch exceptions thrown by the function average( ). The Exception object is created?with a message and error code?and thrown from the average( ) function if the value of $n is zero. Example 4-10 calls the average( ) function inside a try block. If average( ) throws an exception, it is caught by the catch block and the formatException( ) function is called to format the caught Exception object $error. When Example 4-10 is run the call to average( ) causes an Exception object to be thrown, and the following is output:

Error 1001: Number of items = 0

        (line: 13 of c:\htdocs\book\example.4-10.php)

If you called the average( ) as shown in Example 4-10 without a try...catch statement, any exceptions thrown wouldn't be caught and PHP 5 terminates the script with a fatal "Uncaught exception" error.

The throw and try...catch statements provide an alterative to calling the PHP exit( ) or die( ) functions that terminate a script. Using throw and try...catch statements allow you to develop applications that can handle exceptional circumstances in a controlled manner. However, exceptions are quite different from the errors and warnings that PHP generates when things go wrong. Unfortunately, a try...catch statement can't be used to catch fatal errors such as divide by zero. (You can suppress errors with the @ operator; we explain how in Chapter 6.) In Example 4-10, the code that implements the average( ) function tests the value of $n before using it in a division to avoid the fatal "Divide by Zero" error.

We discuss the management of PHP errors and warnings in Chapter 12.