Books / The PHP Programming Language / Chapter 11
Error Handling & Exceptions in PHP
Modern versions of PHP support error handling through the use of exceptions. PHP has
several different predefined types of exceptions and also allows you to define your own
exception types by creating new classes that inherit from the generic Exception
class.
PHP uses the standard try-catch-finally
control structure to handle exceptions and
allows you to throw
your own exceptions.
Throwing Exceptions
Though PHP defines several different types of exceptions, we’ll only cover the generic
Exception class. We can throw an exception in PHP by using the keyword throw
and creating a new Exception
with an error message.
throw new Exception("Something went wrong");
By using a generic Exception
, we can only attach a message to the exception (which
can be printed by code that catches the exception). If we want more fine-grained control
over the type of exceptions, we need to define our own exceptions.
Catching Exceptions
To catch an exception in PHP you can use the standard try-catch
control block.
Optionally (and as of PHP version 5.5.0) you can use the finally
block to clean up any
resources or execute code regardless of whether or not an exception was raised. Consider
the simple task of reading input from a user and manually parsing its value into an
integer. If the user enters a non-numeric value, parsing will fail and we should instead
throw an exception. Consider the following function:
function readNumber() {
$input = readline("Please enter a number: ");
if (is_numeric($input)) {
$value = floatval($input);
} else {
throw new Exception("Invalid input!");
}
}
Elsewhere in the code, we can surround a call to readNumber()
in a try-catch
statement:
try {
readNumber();
} catch (Exception $e) {
printf("Error: exception encountered: ".$e -> getMessage());
exit(1);
}
In this example, we’ve simply displayed an error message to the standard output and exited
the program. We’ve made the design decision that this error should be fatal. We could
have chosen to handle this error differently in the catch block. The $e->getMessage()
prints the message that the exception was created with. In this case, "Invalid input!"
.
Creating Custom Exceptions
As of PHP 5.3.0 it is possible to define custom exceptions by extending the Exception
class. To do this, you need to declare a new class. (We’ll cover classes and objects in
another chapter.) For now, we present a simple example. Consider the example in the previous
chapter of computing the roots of a quadratic polynomial. One possible error situation
is when the roots are complex numbers. We could define a new PHP exception class as
follows:
/**
* Defines a ComplexRoot exception class
*/
class ComplexRootException extends Exception {
public
function __construct($message = null,
$code = 0,
Exception $previous = null) {
// call the parent constructor
parent::__construct($message, $code, $previous);
}
// custom string representation of object
public
function __toString() {
return __CLASS__.
": [{$this->code}]: {$this->message}\n";
}
}
Now in our code we can catch and even throw this new type of exception:
if( $b*$b - 4*$a*$c < 0) {
throw new ComplexRootException("Cannot Handle complex roots");
}
Multiple Catch Blocks
try {
$r1 = getRoot($a, $b, $c);
} catch (ComplexRootException $e) {
//handle here
} catch (Exception $e) {
//handle all other types of exceptions here
}
Review the code above. In it, we have two catch
blocks. Since we can have multiple types of
exceptions, we can catch each different type and handle them differently if we choose.
Each catch
block catches a different type of exception. The last catch
block was
written to catch a generic Exception
. Much like an if-else-if
statement, the first
type of exception that is caught is the block that will be executed and they are all
mutually exclusive. Thus, a generic “catch all” block like this should always be the last
catch
block. The most specific types of exceptions should be caught first and the most
general types should be caught last.