Trouble Shooting Wiki

Error Handling - Joomla 1.5 Development Cookbook

From TroubleshootingWiki

Jump to: navigation, search
Error Handling - Joomla 1.5 Development Cookbook
Official Page
Project Documentation
Download
Source Book
200px-1847198147.jpg
ISBN 978-1-847198-14-3
Publisher Packt Publishing
Author(s) James Kennard

Joomla! has its very own way of dealing with errors. Our gateway to this is the static JError class. There are three error levels defined by Joomla! Error, Warning, and Notice. These should sound very familiar to PHP developers because they have the same names as the built-in PHP errors.

In this tutorial, we make the distinction between PHP errors and Joomla!errors by referring to Joomla! errors as J!errors.


Like their PHP counterparts, J!errors have a corresponding integer value that can be used to build bit masks. In fact, the J!error integers are the same as that for the three basic PHP errors. The following table shows different J!errors, their corresponding values, PHP constants, and a brief description of when each should be used.

Value J!error Constant Description

1

Error E_ERROR Fatal error, which will gracefully stop the script

2

Warning E_WARNING Non-fatal error

8

Notice E_NOTICE Negligible problem which has not affected execution


For a complete description of PHP error constants, refer to the official PHP documentation at http://php.net/manual/errorfunc. constants.php.


Contents

[edit] Raising and Error Level J!Error

This recipe explains how to raise a J!error of the level error. We should use this type of J!error when we encounter a fatal problem, that is, when the problem cannot be overcome and execution needs to stop. The nice thing about this approach is that although the J!error will be fatal, the termination of the script will be graceful and will provide the user with an understandable error page.

How to do it?

To raise a fatal J!error, we use the static JError::raiseError() method. This method requires two parameters, an error code and a message. For example:

// raise an internal server error
JError::raiseError(
500,
JText::_('INTERNAL SERVER ERROR')
);

Notice that the second parameter is translated using JText.

The error code is used in the HTTP response headers and, therefore, must be a valid HTTP error code. For a complete guide to valid HTTP error codes, refer to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Generally, we will use the following codes: 500 (internal server error), 404 (resource not found), 401 (access denied unauthorized), and 403 (access denied forbidden).

It is a good idea to use jexit() directly after raising a fatal J!error. It is possible to change the way errors are handled, thus placing a call to jexit() directly after raising an error will guarantee that the script stops executing.

// raise an internal server error
JError::raiseError(
500,
JText::_('INTERNAL SERVER ERROR')
);
// make sure the JError is fatal jexit(JText::_('INTERNAL SERVER ERROR'));

Clean up after yourself

Prior to raising an error, it might be necessary to clean up any loose ends; for example, undoing what has already been completed during the execution of the script. Failure to do this could result in security weakness CWE-459.

Raising an error in Joomla! will terminate script execution. Unlike the jexit() function and the PHP exit() and die() functions, it will create a user-friendly error message. The following is an example of an error message a user might receive should he or she encounter a fatal error. This output is generated using the error template located in the templates/system/error.php file. It is possible to override this template file in a site template extension.


It can be useful to enable site debugging when errors are encountered, as this will produce a trace showing the exact point of failure in the code. Remember that debugging should never be enabled on live sites because of security considerations.

We can pass a third parameter to JError::raiseError() in which we can place data that will provide us, as a developer, with a more verbose response. However, it should be noted that this extra information is not outputted by the default error templates for security reasons.

JError::raiseError(
500,
JText::_('INTERNAL SERVER ERROR'),
$someVerboseErrorInformation
);

[edit] Raising a Warning level J!Error

In this recipe, we will explore how to raise a warning-level J!error. These J!errors are specifically for use when an error occurs that is not fatal, but alters the actions taken by the script.

How to do it?

To raise a warning, we use the static JError::raiseWarning() method. This method requires two parameters, an error code and a message. This type of J!error is often raised when input validation fails. For example, if a required form field is empty, we might do this:

JError::raiseWarning(
500,
JText::_('PLEASE SUPPLY A VALUE FOR FORM FIELD X')
);

Notice that the second parameter is translated using JText.The purpose of the error code in the context of a warning is not entirely clear. Due to the way in which warnings are handled, the error code is not really put to good use. The de-facto standard is to use the HTTP-style error code 500, which equates to internal server error.

Stick to HTTP error codes

It is best to stick to HTTP error codes when raising warnings. Remember that handling of J!errors can be altered and that for fatal errors, the code is used in the HTTP response. For a complete list of HTTP error codes, refer to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

Warnings are displayed at the top, or near the top of the page. The exact location of the warning and the look and feel of the warning will depend on the site template. The following three examples are based on the templates that are bundled with Joomla! 1.5 (rhuk_milkyway, beez, and ja_purity):

When we redirect the browser using the JApplication::redirect() method, all warnings are persisted. That is to say, if we raise a warning and then redirect to another page, the warning will be displayed on the next page.

We can also opt to pass a third parameter in which we can place data that will provide us, as a developer, with a more verbose response. It should, however, be noted that this extra information is not outputted by any of the default templates.

JError::raiseWarning(
500,
JText::_('AN ERROR OCCURED'),
$someVerboseErrorInformation
);

As warnings are not fatal, it can be useful to grab the return value of JError::raiseWarning(). This value will be a JException object, which includes handy debugging information about the error. It is common to add this value to a JObject, typically the current object in which the error occurred:

// raise warning
$exception = JError::raiseWarning(
500,
JText::_('AN ERROR OCCURED'),
$someVerboseErrorInformation
);
// assign warning to the current object
$this->setError($exception);

To learn how to raise a fatal J!error, refer to the previous recipe, Raising an error-level J!error. Alternatively, to raise a lesser J!error, refer to the next recipe, Raising a notice-level J!error.

[edit] Raising notice level J!error

In this recipe, we explore the least invasive of the J!error levels. A J!error notice is informational. It should only indicate trivial problems that are expected to occur periodically, but do not affect the flow of the script execution.

To raise a notice, we use the static JError::raiseNotice() method. This method requires two parameters, the error code and a message. For example, if a form did not include a value but a default is known, we might do the following:

JError::raiseNotice(
500,
JText::_('NO VALUE FOR FORM FIELD X, ASSUMED VALUE Y')
);

Notice that the second parameter is translated using JText. In practice, we would be more likely to use the static JText::sprintf() method. This is because we can pass the field name and the assumed value to this method separately, thus removing the need for hardcoded values in the translations.

As with the J!error warnings, the purpose of the error code is not clear. The de-facto standard is to use the HTTP-style error code 500, which equates to internal server error.

Stick to HTTP error codes

It is best to stick to HTTP error codes when raising warnings. Remember that handling of J!errors can be altered and for fatal errors, the code is used in the HTTP response. For a complete list of HTTP error codes, refer to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.

Notices are not success messages

It is tempting to think of notices as being suitable for success messages; for example, Some items successfully saved. But this is not the case. Anything that we raise through JError is an error by definition. To create a success message, refer to the next recipe, Enqueuing a message.

Notices are displayed at the top of the page, and are useful for informing users about minor problems. Unlike warnings, notices generally indicate an error that has had no discernable effect on the execution of the script; for example, failure to send an email notification.

The exact look and feel of the notice will depend on the site template. The following three examples are based on the templates that are bundled with Joomla! 1.5 (rhuk_milkyway, beez, and ja_purity):

When we redirect the browser using the Japplication::redirect() method, all notices are persisted. That is to say, if we raise a notice and then redirect to another page, the notice will be displayed on the next page.

What actually occurs when a J!error is raised is determined by the J!error handling options. This can be changed at any time. For more information, refer to the Changing the default error handling recipe later in this tutorial.

For details about including extra information in the J!error and using the returned value of JError::raiseNotice(), refer to the There's more section of the previous recipe. Note that JError::raiseNotice() works in the same way as JError::raiseWarning(). So, much of the recipe information is the same.

[edit] Enqueuing a message

It can be useful to pass informational messages to the user. For example, we might want to inform users that an action has been performed successfully, or that the page they are viewing is not up-to-date. This recipe explains how to use the application message queue to create information messages that will be displayed as a part of the site template.

To enqueue a message, we must first gain access to the global JApplication object.

// get the application
$app =& JFactory::getApplication();

It is possible to use global $mainframe or even $GLOBALS['mainframe'] instead of JFactory::getApplication(). Although this is acceptable, it is considered deprecated and should be avoided.

To enqueue a message, we use the JApplication::enqueueMessage() method to which we pass the message we want to enqueue. </pre> // Add a message $app->enqueueMessage(JText::_('AN ENQUEUED MESSAGE')); </pre>

Redirecting

If we want to display a message directly after a redirect, there is an easier way! We can use the (optional) second JApplication::redirect() parameter to enqueue a message.

The global JApplication object maintains a queue of messages. It is essential that the messages are stored in a queue: Queues are FIFO (First-In-First-Out) data structures. This means that when messages are outputted, they appear in the same order in which they were inserted into the queue.

The message queue is persistent. For this reason, when we redirect the browser using the JApplication::redirect() method, the message queue is retained. That is to say, if we enqueue a message and then redirect to another page, the message will be displayed on the next page.

Messages consist of two parts: the message itself and the type of message expressed as a string. The message type is usually a message, notice, or error. The type of the message affects its appearance; the exact look and feel of the messages will depend on the site template.

When we use the JApplication::enqueueMessage() method, the message that is created defaults to the message type. The following three example messages are of the message type as displayed by the templates that are bundled with Joomla! 1.5 (rhuk_milkyway, beez, and ja_purity):

The message type notice is used specifically for J!errors raised as notices. And, somewhat confusingly, a message type of error is used specifically for J!errors raised as warnings.

When we enqueue a message, we are required to supply the first parameter, the message. We can also pass a second parameter, the message type. By default, this is message. For example, we could enqueue a message of the custom type information.

// Add an information message
$app->enqueueMessage(
JText::_('AN INFORMATION MESSAGE'),'information'
);

In an HTML response, the message type normally equates directly to a CSS class name. We say normally because this is determined by the way in which the site template renders the message queue. If we wanted to use an alternative message type, we should create some corresponding CSS. For example, we could add some CSS to make an information message look like a Wikipedia message.

$style = "/* Informative Messages */
dl#system-message dt.information {
display: none;
}
dl#system-message dd.information ul {
background : #FBFBFB url(someimage.png) no-repeat scroll 4px center;
border : 1px solid #AAAAAA;
border-left: 10px solid #F28500;
color : #000000;
padding : 8px 8px 8px 25px;
}";
$doc =& JFactory::getDocument();
$doc->addStyleDeclaration($style);

This will create the following message:

Let's compare it to a Wikipedia citation message:

[edit] Changing the default J!error

By default, J!error errors result in a fatal script termination that first displays a user-friendly error message. On the other hand, J!error warnings and J!error notices enqueue messages ready to be displayed at the top of the page when it is rendered. We can change the behavior of all of these.

To alter the handling of J!errors, we use the static JError::setErrorHandling() method. This requires two parameters the error type for which we want to modify the handling, and

the handler (also known as the mode) we want to use. An explanation of the J!error types and the corresponding constants is provided in the tutorial introduction.

We will use J!error notices as an example. As J!error notices are informative but should not affect the script flow, we can safely change the mode to Ignore.

// ignore all notices from this point forward. JError::setErrorHandling(E_NOTICE, 'Ignore');

Conversely, we could choose to output a more complete picture of the error. The Verbose mode outputs the error details, including the extra information that can be passed when the error is raised.

// output everything we know about the warning. JError::setErrorHandling(E_WARNING, 'Verbose');

The Verbose mode should be used with caution. It outputs information that could potentially allow a malicious user to glean an unprecedented level of understanding about our system, which could be used to form a basis for an attack, CWE-209.


It is generally assumed that raiseError() will stop the script. Therefore, it is not a good idea to change the handling of E_ERROR unless the alternative mode also stops the script execution.

How it works?

When an error is raised with JError, one of the modes described in the following table will be used. Each mode is technically a static method in the JError class, which can be invoked when an error is raised.

Mode Method Description
Ignore handleIgnore Error is ignored
Echo handleEcho Prints the JException message to screen
Verbose handleVerbose Prints the JException message and back-trace the information to screen
Die handleDie Terminates the application and prints the JException message to screen
Message handleMessage Adds a message to the application queue
Log handleLog Adds a log entry to the application error log
Trigger handleTrigger Triggers a PHP error
Callback handleCallback Calls a static method in another class

Unfortunately, it is not possible to set the handling such that several handlers are used. For example, Log and then Die. However a solution to this can be achieved using the Callback mode, as described in the next section.


The most flexible of all the modes is Callback. This mode allows us to use our own code to handle the J!error. In order to specify the function or method we want to handle the J!error, we must provide the optional third parameter when calling the static JError::setErrorHandling() method. The following example tells Joomla!to invoke the myErrorHandler function when a J!error error is raised:

// use the function myErrorHandler to deal with E_ERROR errors
JError::setErrorHandling( E_ERROR,
'Callback',
'myErrorHandler'
);

The third parameter is of the PHP pseudo type, callback. For more information, refer to http://php.net/manual/language.pseudo-types.php.

In order for this example to work, we must declare the myErrorHandler()function. In the following example, we take advantage of the J!error modes Log and Die by invoking the corresponding static methods in the JError class:

/**
* Log error and die
*
@param JException $error Error that needs handling
@param array $options Handling options
*/
function &myErrorHandler($error, $options) {
// Log the error
JError::handleLog($error, $options);
// End the script
JError::handleDie($error, $options);
// all done return $error;
}

Take note of the function signature. When this function is called, it will be passed a JException object which encapsulates the error information, and in some instances, a variable containing options that can be used to change the way in which the function operates.

The $options parameter is used only by the JError::handleCallback() method. It is however good practice to pass this parameter to the other methods. Notice that we return the $error parameter. This is not really required in our example because the JError::handleDie() method will stop the script from executing anyway. All functions and methods that handle an error should return the original JException object.

To avoid interfering with J!errors, it can be a good idea to define our own J!error levels. This is especially important if we want to use radically different modes to handle our J!errors. For more information, refer to the next recipe, Handling and raising a bespoke J!error.

[edit] Handling and Rasing a bespoke J!error

Sometimes we may want to handle our errors in a very different way from the normal J!error types error, warning, and notice. We can separate our J!errors from the regular J!errors by defining bespoke J!error levels. This ensures we do not interfere with Joomla! and that we maintain a logical separation of the J!error types.

To register a new error level, we use the static JError::registerErrorLevel() method. This method accepts the following three parameters:

  • The error level represented as an integer
  • The human-readable name of the error level
  • The error mode (optional)

For more information about error modes, refer to the previous recipe, Changing the default error handling. In the following example, we register a new error level using <code.Error::registerErrorLevel()</code>:

// declare the error level constant define('BESPOKE_ERROR', 32768);
// register the error level with JError
$registerd = JError::registerErrorLevel( BESPOKE_ERROR,'Bespoke Error'
);

It is important to check the return value of JError::registerErrorLevel(). If the value is false, it indicates that registration of the error level was not successful because the error level has already been registered. Under these circumstances, it is generally best to stop the script.

if (!$registered) { JError::raiseError(500,
JText::_('BESPOKE ERROR LEVEL ALREADY DEFINED')
);
}

As we mentioned, there is an optional third parameter that defines the J!error mode. By default, the J!error mode is Ignore. To use a different J!error mode, we simply supply the name of the mode, as defined in the previous recipe, Changing the default error handling.

One problem exists with the static JError::registerErrorLevel() method. If we want to use a J!error mode that requires options for example, the Callback mode we cannot do this when we register the error level. Instead, we must change the mode afterwards, as described in the previous recipe.

To use our new J!error level, we must use the static JError::raise() method. However, because this method signature is quite complex, it is easiest to create a function or method that calls this for us, similar to the raiseError(), raiseWarning(),and raiseNotice() methods with which we are likely already familiar.

/**
* Raise a bespoke error
*
@param int $code Error code
@param string $msg Error message
@param mixed $info Additional error information
@return JExcpetion
*/
function &raiseBespokeError($code, $msg, $info = null) {
$exception =& JError::raise( BESPOKE_ERROR,
$code,
$msg,
$info, true
);
return $exception;
}

This significantly reduces the effort required to actually raise a bespoke error. Notice that the JError::raise() method accepts five parameters, while our function only accepts three. Of these five parameters, only two are required.

As Joomla! purposely uses error-level codes that can be used in bit patterns, it is generally a good idea to stick to binary values. Joomla! uses three error-level codes. They are 1, 2,and 8. However, it shares these with the PHP equivalents. Therefore, instead of specifying a value of 16 for the next new error level, it is preferable to use the next available code, that is, 215 or 32768.

All of the J!errors are ultimately raised using the static JError::raise() method. This method accepts five parameters, described in order in the following table. Note that $info and $backtrace are not required.

Parameter Default Description
$level J!error level
$code Error code specific to the error that is being raised, usually an HTTP error code; for example, 500 is an internal server error
$msg Human-readable message that describes the error
$info null Additional information about the error
$backtrace false Option to include debug information, which can be used to trace the source of the error

To modify the handling of J!errors, refer to the previous recipe, Changing the default error handling.

[edit] Logging errors and events using Jlog

This recipe explains how to add entries to a log file. We can either add entries to the default Joomal! error log, or we can create our own log files in one easy step. Although JLog is a part of the joomla.error library namespace, this recipe is not suited only for logging errors. We can use JLog to create logs for anything!

Before we attempt to use the JLog class, we must import it.

// import JLog jimport('joomla.error.log');

The first thing we need is an instance of the JLog class. To get this, we use the JLog::getInstance() method. In its most basic form, this method doesn't require a single parameter! Notice that we use the =& assignment operator to ensure that we get a reference to the JLog object, and not a copy.

// get an instance of JLog
$log =& JLog::getInstance();

Alternatively, if we want to create our own log file in the Joomla! log folder, we need to pass the name of the log file to the method. If the error log file does not currently exist, it will be created when we log the first entry.

// get an instance of JLog for myerrors log file
$log =& JLog::getInstance('myerrors.php');

Now to the good bit adding entries to the log file. For this, we use the JLog::addEntry() method. Entries are expressed as arrays. By default, an entry should contain a level, status, and comment. The date, time, and client's IP address will be automatically added to the entry.

// create entry array
$entry = array(
'LEVEL' => '1',
'STATUS' => 'SOME ERROR:',
'COMMENT' => 'Some error occurred'
);
// add entry to the log
$log->addEntry($entry);

The purpose of LEVEL is unclear. There are no examples in Joomla! where this is used, nor is there any documentation explaining its purpose. It is acceptable to omit elements from a log entry. In these instances, a dash will occur in the log file.

The JLog class wraps up the whole logging process for us. We don't need to create the log file, nor do we need to deal with dates, times, and IP addresses. When we add a new entry, a log file will be created if it does not exist. Log files include useful headers that describe the log file format and prevent direct access to the log file, as shown in the following example:

#<?php die('Direct Access To Log Files Not Permitted'); ?>
#Version: 1.0
#Date: 2009-07-02 10:46:10
#Fields: date time level c-ip status comment
#Software: Joomla! 1.5.11 Production/Stable [ Vea ] 03-June-2009 03:30

Notice that the first line of the header includes some PHP. This prevents users from snooping through our error logs. This is why it is important to make sure that our log file is a PHP file.

The JLog::getInstance() method accepts up to three parameters: the name of the log file, an options array, and a base path.

The options array only uses one option, a format string. Format strings are plain-text strings that include field names encapsulated in curly braces. The field names are ultimately substituted for the corresponding entry elements. By default, the format is:

{DATE}\t{TIME}\t{LEVEL}\t{C-IP}\t{STATUS}\t{COMMENT}

The {DATE}, {TIME}, and {C-IP} fields are automatically generated when adding entries. Therefore, we can use these as we please in our format.

The final parameter is the base path, or rather the folder in which the error log is located. By default, this is the Joomla! log folder.

In the following example, we create a bespoke error log located in our component's log folder:

$file = 'myerrors.php';
$format = "{DATE}\t{TIME}\t{C-IP}\t{USER}\t{DESCRIPTION}";
$path = JPATH_COMPONENT . DS . 'logs';
// get JLog instance
$log = JLog::getInstance(
$file,
array('format' => $format),
$path
);

We can now start adding entries to the log file as per the previous example. However, this time our entry should include the elements USER and DESCRIPTION, as expressed by the format string. The following is an example of the bespoke log file:

#<?php die('Direct Access To Log Files Not Permitted'); ?>
#Version: 1.0
#Date: 2009-07-02 10:46:10
#Fields: date time c-ip user description
#Software: Joomla! 1.5.11 Production/Stable [ Vea ] 03-June-2009 03:30
2009-07-02 10:46:43 127.0.0.1 admin Some error occurred

[edit] Throwing exceptions with PHP 5

In PHP 4, we are used to functions returning false or something similar on failure. The problem with this is that the failure is handled only if the invoking code bothers to check the returned value. Exceptions provide a more robust solution that forces the failure to be handled. This recipe looks at how we create, or rather how we throw, an exception in PHP 5. This recipe applies only to extensions being built specifically for PHP 5.To throw an exception using PHP 5, we use the throw statement. In its most basic form, it will work like this:

throw new Exception();

Exceptions are represented as objects. In this instance, we have used the most basic of all exception classes, Exception. This class accepts two optional parameters, an error message and an error code.

throw new Exception(
JText::_('SOMETHING HAS GONE AWRY'),
500
);

We do not have to create the Exception object as part of the throw statement.

$myException = new Exception($message, $code);
throw $myException;

When we declare a function or a method that might throw an exception, it is a good idea to include a phpDoc [mailto:@throws @throws] tag to this effect in the function or method DocBlock.

/**
* My function that does something
*
@todo implement method
@throws Exception Function might throw an exception
*/
function myFunction() {
}

The [mailto:@throws @throws] tag is normally used in the following form:

[mailto:@throws @throws] [classname [description]]

A [mailto:@throws @throws] tag should be added for every type of exception the function or method can throw.

Exceptions stop the normal script flow. As soon as an exception is thrown, it must be handled. Failure to handle an exception will result in an ungraceful fatal error. To learn about handling exceptions in PHP, refer to the next recipe, Catching exceptions with PHP 5.

Java programmers may be interested to know that PHP 5 does not support checked exceptions. For more information about checked exceptions, refer to http://java.sun.com/docs/books/tutorial/essential/ exceptions/.

It is common practice to extend the built-in Exception class to provide greater specialization for specific exceptions. For example, we could create an exception class that deals exclusively with verification failures:

class VerificationException extends Exception {
/**
* Expected value
*/
protected $expectedValue;
/**
* Actual value
*/
protected $actualValue;
/**
* Overrides Exception constructor
*
@param mixed $expectedValue Expected value
@param mixed $actualValue Actual value
*/
public function construct($expectedValue, $actualValue) {
$message = 'Actual value ' . $actualValue
. ' does not equal expected value '
. $expectedValue;
parent:: construct($message, 500);
$this->expectedValue = $expectedValue;
$this->actualValue = $actualValue;
}
}

When defining additional class properties, it is best practice to define them as protected and to create suitable accessor methods; for example, getActualValue(). We have not done this in the example for ease of reading.

The Standard PHP Library includes a number of useful predefined Exception classes. It is worth noting these before creating our own Exception classes. For more information, refer to http://php.net/manual/spl.exceptions.php.

Another reason for extending the built-in Exception class is to provide greater control when it comes to handling exceptions. For example, it can be beneficial to create a new class that extends Exception, but does not add to it because the type of exception determines what can handle it.

As stated in the tutorial introduction, looking into the future, in Joomla! 1.6 (in development at the time of writing), the JException class will be a child of the built-in PHP 5 Exception class, and thus will be throwable.

This recipe is very much designed to be used in tandem with the next recipe, which describes how to handle an exception after it has been thrown.

[edit] Catching exception with PHP 5

Once an exception is thrown, it must be dealt with before normal script execution can continue. Continuing the throw analogy, handling an exception is known as catching. This recipe explains how to catch exceptions.

We use the try and catch blocks to catch PHP exceptions. Within the try block, we place the code that could potentially throw an exception. Within the catch block, we place the code that deals with an exception if it is thrown in the try block. The following is a basic example:

try {
myFunction();
} catch (Exception $e) {
echo $e;
}

Exceptions can be specialized from the built-in PHP Exception class. That is to say, as shown in the previous recipe, we can create subclasses from the PHP Exception class, and we can throw these.

We can create a catch block that deals specifically with specialized Exception objects by changing the catch statement. We could change our example to only catch VerificationException objects (as defined in the previous tutorial).

try {
myFunction();
} catch (VerificationException $e) {
echo $e;
}

It is possible to define several catch blocks, each with a specific type of exception in mind.

try {
myFunction();
} catch (VerificationException $e) {
echo 'Verification Failed';
} catch (Exception $e) {
echo $e;
}

Unlike some languages, PHP 5 does not support the finally statement. In PHP, all exceptions must be derived from the built-in Exception class. Thus, the last catch statement shown in the above example will catch any exception that has not been handled by a prior catch block.

The try block is very simple: between the curly braces, there is some code that could cause an exception to be thrown. We can place as much or as little code in the try block as we like.

PHP 5 introduces type hinting. We see an example of this in catch statements, such as catch (Exception $e). This equates to "Catch exceptions of type, Exception and assign the exception to $e."

When an exception occurs, PHP will work its way through the catch statements looking for a suitable catch block. Each catch statement is interrogated until a catch block that is capable of handling the exception is located. Therefore, the order of the catch blocks is important.

A try and catch block does not have to deal with all exceptions. If a suitable catch block is not found, the script will move up through the stack of try blocks until it finds a suitable catch statement, or until there are no options left, at which point the script will end fatally.

Once an exception has been successfully handled, the script will resume after the try and catch block that successfully handled the exception. That is to say, the script will not continue where it left off. For this reason, it is generally considered bad practice to create try and catch blocks that encapsulate unnecessarily large blocks of code.

The way in which the examples deal with the exceptions is not particularly tactful. Simply outputting an exception as a string does not overcome the error, nor does it produce user-friendly output. But perhaps more importantly, it poses a potential security weakness because it reveals a complete trace to the point of failure, including the full path to each file and the line on which code was invoked leading to the failure, CWE-209.

A more appropriate way of dealing with exceptions is to provide the user with a user-friendly error message and in extreme instances, end the script gracefully. We can get the basic gist of the exception from the exception message without giving away the details. We retrieve the message using the JException::getMessage() method. We can exit gracefully by raising a fatal HTTP 500 J!error message.

try {
doSomething();
} catch (Exception $e) {
// create a user friendly error message
$message = 'An exception occurred: '.$e->getMessage();
// exit Joomla! gracefully
JError::raiseError(500, $message, $e);
// for good luck, make sure we do actually stop now!
jexit($message);
}

The following table describes some handy methods we can use to interrogate PHP Exception objects:

Method Description
getMessage() Human-readable exception message
getCode() Code that describes the type of exception
getFile() File in which the exception was thrown
getLine() Line on which the exception was thrown
getTrace() Array that describes the point of failure in the same way as the PHP function debug_backtrace()
getTraceAsString() Human-readable equivalent of getTrace()


Clean up after yourself

We should always clean up after an exception occurs. For example, if we are halfway through a process, it may be necessary to undo the first part of the process. Failure to do this could result in a security weakness CWE-459.

[edit] Additional References

  • For instructions on Handling Joomla! Errors, click here
  • For instructions on Creating Joomla v1.0 Templates, click here
  • For instructions on Customizing Joomla v1.0 Templates, click here
  • For instructions on Creating Accessible Joomla Templates, click here
  • For instructions on Installing Joomla! 1.5, click here
  • For instructions on Debugging Joomla! 1.5x, click here
  • For instructions on Error Handling - Joomla 1.5 Development Cookbook, click here
  • For instructions on Debugging and validating Joomla Templates, click here

[edit] Source

The source of this content is Chapter 11: Error Handling - Joomla 1.5 Development Cookbook of Joomla! 1.5 Development Cookbook [RAW by James Kennard (Packt Publishing, 2009).

Personal tools