Exceptions


Exceptions are an entirely new concept to PHP 5 and represent the object-oriented approach to triggering a nonfatal error in PHP scripts. In PHP 4, the only way to trigger an error was to use the trigger_error() function and then process that error within a custom error handler set by set_error_handler(). Exceptions, on the other hand, enable you to cause errors as well as deal with errors in a much more reasonable fashion.

Understanding the Call Stack

To understand how exceptions work, first you must understand the concept of a call stack. A call stack is, in essence, a record of the order by which functions and methods have been called within your script. Consider the following script example:

 <?php      function firstFunction() {           secondFunction();      }      function secondFunction() {           thirdFunction();      }      function thirdFunction() {           echo "Hello, world!";      }      firstFunction(); ?> 

When this script executes, it is clear that firstFunction() will call secondFunction(), which will in turn call thirdFunction(). What is the call stack when we are within the thirdFunction() call? It would look something like the following:

 thirdFunction(); secondFunction(); firstFunction(); 

NOTE

Not familiar with the concept of a stack? Chances are you know exactly what a stack is but have never heard it called such. If you were to represent a computer stack (be it a call stack or otherwise) in the real world, look no further than a Pez candy dispenser! The dispenser starts off empty until you "push" candy into it, causing the previous piece to be buried. Then, as you eat the candy you "pop" one off the top. The same concept applies to computer stacks. You "push" data onto the stack and then "pop" it off as it's needed.


Looking at this, it is clear that a call stack is nothing more than a record of the order that the functions were called. The first function pushed onto the call stack is firstFunction() because it was the first function called and, as expected, the current function, thirdFunction(), is at the top of the stack. As these function calls return, they are then popped off the stack until we are back in the global scope.

The concept of the call stack is an important part of exception handling, as you will see shortly.

The Exception Class

In practical terms, exceptions are instances of classes that contain information about an error that has occurred during the execution of your script. PHP 5 provides such a class internally, properly named the Exception class. This class implements a number of methods that provide valuable debugging information about the error that has occurred. The class definition for the Exception class is found in Listing 13.25:

NOTE

Listing 13.25 does not provide code for methods in the Exception class, because it is an internal PHP class.


Listing 13.25. The Class Definition for the Exception Class
 <?php      class Exception {           protected $message;           private $string;           protected $code;           protected $file;           protected $line;           private $trace;           function __construct($message = "", $code = 0);           function __toString();           public function getFile();           public function getLine();           public function getMessage();           public function getCode();           public function getTrace();           public function getTraceAsString(); `     } ?> 

The purpose of many of the methods implemented within the base Exception class is fairly self-evident. Unless specified, none of the methods within the Exception class accepts any parameters. Exceptions in PHP contain two primary values: the string message describing the error that has occurred and an integer code representing that error. When constructing the exception, either may be omitted if desired. By default, PHP will automatically assign to the exception the line and filename where the error occurred, as well as a stack trace representing the path of execution that resulted in the error.

It is also important to note that the Exception class may be extended as needed, enabling you to implement your own version of the Exception class to suit your particular needs.

Throwing and Catching Exceptions

In the OOP design model, when an error occurs an exception is created and "thrown." This means that when an exception is generated through the course of execution of a script, the exception is propagated back up the call stack until one of two things happens:

  • It is caught in one of the functions in the stack.

  • It reaches the top of the stack without being caught.

Throwing an exception from within your scripts is done using the throw statement and passing it an instance of an exception to throw, as shown in Listing 13.26.

Listing 13.26. Throwing an Exception
 <?php      class ThrowExample {           public function makeError() {                throw new Exception("This is an example Exception");           }      }      $inst = new ThrowExample();      $inst->makeError(); ?> 

In Listing 13.26, when the makeError() method is executed, it generates an exception that will propagate back through the call stack, which in this case is only a single level (back to global scope). Because there is no logic to catch this exception, the result will be a script-terminating error with the following error message:

 Fatal error: Uncaught exception 'exception' with message 'This is an example Exception'            in /listing_13_26.php:4 Stack trace: #0 /listing_13_26.php(8): ThrowExample->makeError() #1 {main}   thrown in /listing_13_26.php on line 4 

As you can see, exceptions provide a much more robust error message than previously available in PHP 4. However, even with a robust error message, it is still always better to recover from an error without a user knowing one occurred. To do this using exceptions, you must use a new PHP 5 language construct called a TRy/catch block.

A TRy/catch block is used to execute a segment of code that may throw an exception and recover. The syntax for a try/catch block is as follows:

 try {      /* code to be executed */ } catch(ExceptionClass $variable) {      /* Code to deal with a caught Exception */ } [ catch (AnotherException $variable) { } ] ... 

Note that ExceptionClass and $variable are only placeholders, for example. In fact, ExceptionClass can be any class that inherits from the internal Exception class. When a try/catch block is used in a PHP script, the following list shows what happens:

1.

Execute the code within the TRy portion of the block.

2.

If no exception occurred within the try block, continue to execute the script beyond the try block.

3.

If an exception occurred, compare the class of the exception to those listed as being caught by the try block.

4.

If the TRy block catches the thrown exception, execute the code within the catch block that caught the error.

5.

If the try block does not catch the exception, continue to propagate the exception through the call stack.

When an exception is caught, the thrown exception object is assigned to the variable named within the catch block ($variable in the previous syntax).

To complete our discussion of exceptions, consider the code in Listing 13.27, which is based on the example found in Listing 13.26:

Listing 13.27. Catching Exceptions in PHP 5
 <?php         class MyException extends Exception {                 /* No new code necessary, just new type of                    Exception */         }         class AnotherException extends Exception {                 /* Again, a shell class to define a different                    type of exception */         }         class ThrowExample {                 public function makeMyException() {                         throw new MyException();                 }                 public function makeAnotherException() {                         throw new AnotherException();                 }                 public function makeError() {                         throw new Exception();                 }         }         $inst = new ThrowExample();         try {                 $inst->makeMyException();         } catch(MyException $e) {                 echo "Caught 'MyException'\n";         }         try {                 $inst->makeAnotherException();         } catch(MyException $e) {                 echo "Caught 'MyException'\n";         } catch(AnotherException $e) {                 echo "Caught 'AnotherException'\n";         }         try {                 $inst->makeError();         } catch(MyException $e) {                 echo "Caught 'MyException'\n";         } catch(AnotherException $e) {                 echo "Caught 'AnotherException'\n";         } ?> 

Although Listing 13.27 is a rather lengthy example, it provides a number of important examples of using try/catch blocks in conjunction with exceptions. In this example, I have created a simple class, THRowExample, which throws three versions of the Exception class: Exception itself, MyException, and AnotherException. I then create an instance of the THRowExample class and trigger all three exceptions using three different try/catch blocks.

When this script is executed, the code within the first try block will be executed, which triggers an exception of type MyException. Because this exception is caught by the try block of the function call, the code within the catch block will be executed. In the second try block I repeat the process, except this time an AnotherException exception is thrown.

In this case, I have specified two types of exceptions that I am willing to catch, so both are compared against the thrown exception. Because the try block does indeed catch the AnotherException exception, its corresponding catch code block is executed.

For the third try block, however, I have thrown an exception that is not caught by any of the provided catch blocks. Even though Exception is the parent of the MyException and AnotherException classes, because it is not the same specific class no match occurs and the exception is propagated resulting in a script terminating error. When actually executed, Listing 13.27 generates the following output:

 Caught 'MyException' Caught 'AnotherException' Fatal error: Uncaught exception 'exception' in /exp.php:18 Stack trace: #0 /exp.php(39): ThrowExample->makeError() #1 {main}   thrown in /exp.php on line 18 

As expected, the first two exceptions are caught by their respective try blocks and the script was able to continue executing. However, the script terminates after calling the makeError() method as it throws an exception which is not caught.

NOTE

Exceptions follow the same object hierarchy as any other class in PHP. Thus, you can catch any exception that occurs with the following TRy/catch block:

 try {      /* execute code */ } catch(Exception $e) {      /* Will be called if any exception is thrown */ } 

Because all exceptions inherit from the Exception internal PHP class, by catching the Exception class itself, the result is the catching of any thrown exception.


Exceptions are incredibly powerful tools for the object-minded programmer. However, always be mindful of their purpose! Never rely on exceptions as a way to control the flow of your application, because that is not their purpose. Throw exceptions only in the event of an actual error during the execution of a method, as if you do not expect them to be caught. For instance, using an exception to indicate a return value (where no real error occurred) is considered bad practice.



PHP 5 Unleashed
PHP 5 Unleashed
ISBN: 067232511X
EAN: 2147483647
Year: 2004
Pages: 257

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net