Programming PHPProgramming PHPSearch this book

13.4. Error Handling

Error handling is an important part of any real-world application. PHP provides a number of mechanisms that you can use to handle errors, both during the development process and once your application is in a production environment.

13.4.1. Error Reporting

Normally, when an error occurs in a PHP script, the error message is inserted into the script's output. If the error is fatal, the script execution stops.

There are three levels of conditions: notices, warnings, and errors. A notice is a condition encountered while executing a script that could be an error but could also be encountered during normal execution (e.g., trying to access a variable that has not been set). A warning indicates a nonfatal error condition; typically, warnings are displayed when calling a function with invalid arguments. Scripts will continue executing after issuing a warning. An error indicates a fatal condition from which the script cannot recover. A parse error is a specific kind of error that occurs when a script is syntactically incorrect. All errors except parse errors are runtime errors.

By default, all conditions except runtime notices are caught and displayed to the user. You can change this behavior globally in your php.ini file with the error_reporting option. You can also locally change the error-reporting behavior in a script using the error_reporting( ) function.

With both the error_reporting option and the error_reporting( ) function, you specify the conditions that are caught and displayed by using the various bitwise operators to combine different constant values, as listed in Table 13-1. For example, this indicates all error-level options:

(E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)

while this indicates all options except runtime notices:

(E_ALL & ~E_NOTICE)

If you set the track_errors option on in your php.ini file, a description of the current error is stored in $PHP_ERRORMSG.

Table 13-1. Error-reporting values

Value

Meaning

E_ERROR

Runtime errors

E_WARNING

Runtime warnings

E_PARSE

Compile-time parse errors

E_NOTICE

Runtime notices

E_CORE_ERROR

Errors generated internally by PHP

E_CORE_WARNING

Warnings generated internally by PHP

E_COMPILE_ERROR

Errors generated internally by the Zend scripting engine

E_COMPILE_WARNING

Warnings generated internally by the Zend scripting engine

E_USER_ERROR

Runtime errors generated by a call to trigger_error( )

E_USER_WARNING

Runtime warnings generated by a call to trigger_error( )

E_USER_NOTICE

Runtime warnings generated by a call to trigger_error( )

E_ALL

All of the above options

13.4.2. Error Suppression

You can disable error messages for a single expression by putting the error suppression operator @ before the expression. For example:

$value = @(2 / 0);

Without the error suppression operator, the expression would normally halt execution of the script with a "divide by zero" error. As shown here, the expression does nothing. The error suppression operator cannot trap parse errors, only the various types of runtime errors.

To turn off error reporting entirely, use:

error_reporting(0);

This ensures that, regardless of the errors encountered while processing and executing your script, no errors will be sent to the client (except parse errors, which cannot be suppressed). Of course, it doesn't stop those errors from occurring. Better options for controlling which error messages are displayed in the client are shown in Section 13.4.4.

13.4.3. Triggering Errors

You can throw an error from within a script with the trigger_error( ) function:

trigger_error(message [, type]);

The first parameter is the error message; the second, optional, parameter is the condition level, which is either E_USER_ERROR, E_USER_WARNING, or E_USER_NOTICE (the default).

Triggering errors is useful when writing your own functions for checking the sanity of parameters. For example, here's a function that divides one number by another and throws an error if the second parameter is zero:

function divider($a, $b) {
  if($b == 0) {
    trigger_error('$b cannot be 0', E_USER_ERROR);
  }
  
  return($a / $b);
}
  
echo divider(200, 3);
echo divider(10, 0);
66.666666666667
Fatal error: $b cannot be 0 in page.php on line 5

13.4.4. Defining Error Handlers

If you want better error control than just hiding any errors (and you usually do), you can supply PHP with an error handler. The error handler is called when a condition of any kind is encountered and can do anything you want it to, from logging to a file to pretty-printing the error message. The basic process is to create an error-handling function and register it with set_error_handler( ).

The function you declare can take in either two or five parameters. The first two parameters are the error code and a string describing the error. The final three parameters, if your function accepts them, are the filename in which the error occurred, the line number at which the error occurred, and a copy of the active symbol table at the time the error happened. Your error handler should check the current level of errors being reported with error_reporting( ) and act appropriately.

The call to set_error_handler( ) returns the current error handler. You can restore the previous error handler either by calling set_error_handler( ) with the returned value when your script is done with its own error handler, or by calling the restore_error_handler( ) function.

The following code shows how to use an error handler to format and print errors:

function display_error($error, $error_string, $filename, $line, $symbols) {
  echo "<p>The error '<b>$error_string</b>' occurred in the file '<i>$filename</i>' 
on line $line.</p>";
}
  
set_error_handler('display_error');
$value = 4 / 0; // divide by zero error
<p>The error '<b>Division by zero</b>' occurred in the file
'<i>err-2.php</i>' on line 8.</p>

13.4.4.1. Logging in error handlers

PHP provides a built-in function, error_log( ) , to log errors to the myriad places where administrators like to put error logs:

error_log(message, type [, destination [, extra_headers ]]);

The first parameter is the error message. The second parameter specifies where the error is logged: a value of 0 logs the error via PHP's standard error-logging mechanism; a value of 1 emails the error to the destination address, optionally adding any extra_headers to the message; a value of 3 appends the error to the destination file.

To save an error using PHP's logging mechanism, call error_log( ) with a type of 0. By changing the value of error_log in your php.ini file, you can change which file to log into. If you set error_log to syslog, the system logger is used instead. For example:

error_log('A connection to the database could not be opened.', 0);

To send an error via email, call error_log( ) with a type of 1. The third parameter is the email address to which to send the error message, and an optional fourth parameter can be used to specify additional email headers. Here's how to send an error message by email:

error_log('A connection to the database could not be opened.', 1, 'errors@php.net');

Finally, to log to a file, call error_log( ) with a type of 3. The third parameter specifies the name of the file to log into:

error_log('A connection to the database could not be opened.', 3, '/var/log/php_
errors.log');

Example 13-5 shows an example of an error handler that writes logs into a file and rotates the log file when it gets above 1 KB.

Example 13-5. Log-rolling error handler

function log_roller($error, $error_string) {
  $file = '/var/log/php_errors.log';
  
  if(filesize($file) > 1024) {
    rename($file, $file . (string) time( ));
    clearstatcache( );
  }
  
  error_log($error_string, 3, $file);
}
  
set_error_handler('log_roller');
  for($i = 0; $i < 5000; $i++) {
    trigger_error(time( ) . ": Just an error, ma'am.\n");
  }
restore_error_handler( );

Generally, while you are working on a site, you will want errors shown directly in the pages in which they occur. However, once the site goes live, it doesn't make much sense to show internal error messages to visitors. A common approach is to use something like this in your php.ini file once your site goes live:

display_errors = Off
log_errors = On
error_log = /tmp/errors.log

This tells PHP to never show any errors, but instead to log them to the location specified by the error_log directive.

13.4.4.2. Output buffering in error handlers

Using a combination of output buffering and an error handler, you can send different content to the user, depending on whether various error conditions occur. For example, if a script needs to connect to a database, you can suppress output of the page until the script successfully connects to the database.

Example 13-6 shows the use of output buffering to delay output of a page until it has been generated successfully.

Example 13-6. Output buffering to handle errors

<html>
<head><title>Results!</title></head>
<body>
<?php
 function handle_errors ($error, $message, $filename, $line) {
   ob_end_clean( );
   echo "<b>$message</b> in line $line of <i>$filename</i></body></html>";
   exit;
 }
 set_error_handler('handle_errors');
 ob_start( );
?>
  
<h1>Results!</h1>
  
Here are the results of your search:<p />
<table border=1>
<?php
 require_once('DB.php');
 $db = DB::connect('mysql://gnat:waldus@localhost/webdb');
 if (DB::iserror($db)) die($db->getMessage( ));
 // ...
?>
</table>
</body>
</html>

In Example 13-6, after we start the <body> element, we register the error handler and begin output buffering. If we cannot connect to the database (or if anything else goes wrong in the subsequent PHP code), the heading and table are not displayed. Instead, the user sees only the error message, as shown in Figure 13-1. If no errors are raised by the PHP code, however, the user simply sees the HTML page.

Figure 13-1

Figure 13-1. Error message instead of the buffered HTML



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.