30 June 2010

Exceptions in PHP

Прочети тази статия на български

In this article:

 

Exceptions

Exceptions and try-catch blocks are introduced in PHP version 5.

Here's an example for the syntax of try-catch:

try {
    ...
} catch (Exception $e) {
    ...
}
First, statements inside the try block are executed. If an exception is thrown PHP ignores next statements until a proper catch block is found, in which case the catch block is executed.

An interesting thing about ignoring next statements (until the next catch block) is that even statements after the try block will be ignored since catch has not been found (and executed) yet.

If there's no matching catch block until the end of the script a Fatal error occurs.

If there's no exception thrown, the whole try block is executed, and the catch one is ignored.

Consider the following example:

function display_text($text) {
    if (!$text)
        throw new Exception('Nothing to display');
    else
        echo $text;
}

try {
    display_text('First line.');
    display_text(); // An exception is thrown, so the block execution breaks here
    display_text('This will be ignored.');
}
// Any statements here would be ignored too - the exception must be caught first
catch (Exception $e) {
    echo 'Exception: ' . $e->getMessage() . "\n";
}
// script continues...
PHP allows catching exceptions from nested levels - in previous example the function we call throws the exception, but instead it could call another function (which calls another function, and so on) which throws the exception. We'll be able to catch that exception too.

 

The Exception object

As seen from the afore example, exceptions are thrown by creating new object and assigning a message to it (throw new Exception()). Later in the script we're able to catch it with catch (Exception $obj_name). Inside the catch block we may use the object's methods to get information about the exception.

Here's a short reference to (most of) the Exception class methods (check the PHP manual on the Exception class for more information):

Exception::__construct ( [ string $message = '' [, int $code = 0 [, Exception $previous = null ] ] ] )
Constructs the exception object (i.e. throw new Exception(...)). $message is the error (exception) message, $code is an optional error parameter, by which an error number might get defined. $previous can be used to link the exception to a previous one (for example, you may have a case when catching one exception results in more exceptions - link to previous exceptions can be linked so at the end all messages could be proceeded).
string    Exception::getMessage()
int       Exception::getCode()
Exception Exception::getPrevious()
Returns the mentioned before message, code, and link to previous exception.
string    Exception::getFile()
Returns the filename of the PHP where the exception was thrown.
int       Exception::getLine()
Returns the line number in the PHP file where the exception occured.
array     Exception::getTrace()
string    Exception::getTraceAsString()
These two methods will return more detailed information such as function name where the exception occured, arguments the function has been called with (filename and line number as provided as well). The difference is that while getTrace() does provide the information as an associated array (['Line']=>23, ['Function']=>'test()' etc.), getTraceAsString() formats that information in one string.

Short example:

...
catch (Exception $e) {
    echo 'Error: '.$e->getMessage().' in "'.$e->getFile().'" at line '.$e->getLine();
}

 

Exception subclasses

class MyException extends Exception {}
class MyOtherException extends Exception {}

function test($var) {
    if ($var > 0) throw new MyException('Positive number');
    if ($var < 0) throw new MyOtherException('Negative number');
    return 0;
}

try { echo test(1); }
catch (MyException $e) { echo 'The number was greater than zero.'; }
catch (MyOtherException $e) { echo 'The number was below zero.'; }
Subclasses of Exception can be defined (in fact, many predefined exception classes exist in PHP), then you may catch different descendants with different catch blocks. Since MyException and MyOtherException are child classes of Exception, instead of two catch(My... $e) we could use one catch(Exception $e) statement and still the exception will be properly caught. One method of dealing with different exceptions would be using many subclasses, and other method could make use of the $code parameter to define the type of error.

 

Why won't this catch the exception?

function read_first_line($filename) {
    try {
        $a = file($filename);
    } catch(Exception $e) {
        return false;
    }
    return $a[0];
}

echo read_first_line('myfile.txt');
This won't work. Still your page will yell something like 'Error: could not open stream...' in case of error instead of 'false'. This is because old PHP functions still don't take advantage of the Exceptions mechanism. The "old" error handling method is used instead but I'll write about that in another article.

No comments:

Post a Comment