If you've written PHP code before you've read this chapter, you're already familiar with PHP errors. However, you've probably not thought much about the different error types and the situations in which they occur. This section discusses errors in detail, and shows you how to change the error reporting levels in PHP and make the most of debugging information during development.
PHP problems break down into four types or levels: errors, parse errors, warnings, and notices. They can occur in four different situations: internally within PHP itself (in the PHP core), during compilation when your script is first loaded, at run time when your script is being executed, or when explicitly triggered by you in your code.
While all this might seem complicated, the variety leads to more informed debugging, configurable error handling, and flexibility across all phases of the development of web database applications. In any case, to some extent it's unavoidable. A missing bracket is always discovered during compilation and aborts the run immediately, whereas division by zero or a failed connection to a database must wait till the script has run up to the point of the error.
Table 12-1 lists the problems and in what situations they occur; for simplicity, we refer to all of the possible problems and situation combinations as errors. The most serious of the error types are the ERROR and PARSE classes: both are fatal, that is, by default they stop script execution and report an error message. The WARNING class is also serious and still reports messages, but by default doesn't stop script execution. The least serious of the errors are in the NOTICE class, which by default don't report messages or stop the script. We discuss how to adjust the default behaviors later in this section.
Constant |
Description |
Halts script? |
---|---|---|
E_ERROR |
Fatal runtime error |
Yes |
E_WARNING |
Non-fatal runtime error |
No |
E_PARSE |
Compile-time parser error |
Yes |
E_NOTICE |
Runtime notice |
No |
E_CORE_ERROR |
Fatal PHP startup error |
Yes |
E_CORE_WARNING |
Non-fatal PHP startup error |
No |
E_COMPILE_ERROR |
Fatal compile-time error |
Yes |
E_COMPILE_WARNING |
Non-fatal compile time error |
No |
E_USER_ERROR |
Fatal programmer-generated error |
Programmer-defined |
E_USER_WARNING |
Non-fatal programmer-generated error |
Programmer-defined |
U_USER_NOTICE |
Programmer notice |
Programmer-defined |
E_ALL |
All of the above |
? |
The ERROR class includes errors such as calling undefined functions, instantiating objects of a non-existent class, and issuing a statement when it isn't allowed (for example, a break or continue outside of a loop). The PARSE class includes syntax errors from missing semicolons, missing quotes and brackets, and statements with incorrect numbers of parameters. The WARNING class covers less serious problems?where a script may be able to continue successfully?such as the MySQL connection problems discussed in Chapter 6, divide by zero errors, passing the wrong number of parameters to a function, and including a file that doesn't exist. The NOTICE class errors are usually minor and informational and include, for example, warnings about using undefined variables.
The WARNING and ERROR class errors can be produced by the PHP core Zend engine, the compilation process, runtime processing, or deliberate triggering by the programmer. Notices can be produced by the latter two. While this sounds complicated to deal with, most of the time the only problems that your code needs to handle after it's deployed are the runtime E_WARNING errors; the E_USER_ERROR, E_USER_WARNING, and E_USER_NOTICE errors may also be handled in your code, and we discuss this later in Section 12.3. We've deliberately omitted E_PARSE, E_ERROR, and E_NOTICE from the list of errors your code needs to worry about: these are usually fixed by the programmer during development.
By default, error messages are displayed to the user agent (usually a web browser), along with whatever output has been produced up to the point the error occurred; the exception is E_NOTICE errors, which are ignored with the default settings. For example, consider the following script that contains an E_WARNING error that's detected at runtime:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Error</title> <body> <h1>Two times!</h1> <?php function double($number) { return $number*2; } print "Two times ten is: " . double( ); print "<br>Two times five is: " . double(5); ?> </body> </html>
The function double( ) is called without its parameter in the first print statement, and so a warning is produced as shown in the Mozilla browser in Figure 12-1. The PHP-generated warning occurs after the HTML <h1> text has been output, but before the output of the print statement that contains the error. Because it's a warning, the script continues, and both print statements produce output. The error itself is useful for debugging: it contains a description of what caused the error, and the source file and line number. We discuss the common sources of errors and how to find them later in this section.
When you use templates, you'll find that the errors are usually output before the output of the script. This is because template output is buffered until you call the show( ) method, while error output is sent directly to the user agent. This can make debugging a little harder, but it does help prevent error messages from being confused amidst the script output.
The E_ERROR runtime errors stop script execution, so the script produces output only up to the point where the error occurred. In the case of templates, it's typical that no output except the error will be produced. Similarly, E_PARSE errors prevent any script output, as the problems are detected before runtime.
During development, the errors produced by PHP are useful tools for debugging your code. For example, suppose you attempt to establish a mysql_connect( ) connection but misspell localhost. This produces the error:
Warning: mysql_connect( ) [function.mysql-connect.html]: Unknown MySQL Server Host 'localhos' (1) in /usr/local/apache2/htdocs/examples/buggy.php on line 18
By default, because a library function is involved, PHP produces a link to the PHP manual function reference for mysql_connect( ), which is shown surrounded by square braces. You can click on this link and visit the manual. However, as discussed in Chapter 6, if you prefix your function calls with @ then these error messages are suppressed.
To support development, it's useful to have a copy of the PHP manual in the document tree of your development environment. To do this, download a copy of the Many Files HTML version from http://www.php.net/download-docs.php. Then create a directory below your htdocs directory and uncompress the file into that directory. For example, if you've followed our Unix installation instructions in Appendix A through Appendix C, you could use mkdir /usr/local/apache2/htdocs/php-manual to create the directory, move the file there, and then uncompress it with bunzip2. If you've followed our EasyPHP installation instructions for Microsoft Windows, create the folder C:\Program Files\EasyPHP1-7\www\php-manual and put the file there. On Mac OS X, use /Library/WebServer/Documents/php-manual. The PHP site has a useful FAQ entry for Microsoft Windows users who aren't familiar with the bzip2 compressed file format: http://au.php.net/manual/en/faq.misc.php#faq.misc.bz2.
After downloading the file, you need to configure your PHP to link to your local manual. To do this, open your php.ini file in an editor and locate the line beginning docref_root =. Change the line to point to your new directory below your document root (for example, docref_root = /php-manual), ensure that the immediately following line reads doc_ref = .html, and that the line ;html_errors = has a semicolon at the beginning. Save the file, and restart your Apache web server using the instructions in Appendix A through Appendix C.
Errors provide useful information when you're debugging your application. However, when it's deployed, displaying PHP errors among the application output is messy, confusing for users, and uninformative for those who need to be alerted to rectify the problems. Most importantly, it's also a security problem: program internals are displayed as part of error messages and these shouldn't be displayed to end users.
Error reporting is configured in PHP in two common ways. First, by setting a global default in the php.ini file; and, second, by setting error reporting on a script-by-script basis. By default, in the php.ini file, you'll find that error reporting is globally set to:
error_reporting = E_ALL & ~E_NOTICE
This means that all error types are reported, except E_NOTICE errors; the & operator is the bitwise AND discussed in Chapter 2, and the ~ is the bitwise NOT used to negate E_NOTICE. The list of possible constants that can be used in shown in Table 12-1.
You can adjust this configuration to suit your requirements by modifying the global default for all scripts or by setting a specific value in a script that's used only in that script. For example, to change the global value to detect only the ERROR and PARSE classes, you can use:
error_reporting = E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR|E_PARSE
By default, all warnings and notices are then ignored; the | operator is the bitwise OR. As before, after making any change to php.ini, you need to restart your Apache web server.
To set an error-reporting level for one script, you can use the error_reporting( ) library function. For example, to detect all error types, you can add:
<?php error_reporting(E_ALL);
to the beginning of the script. The function also takes a constant from Table 12-1 as the parameter, and you can use the bitwise &, |, and ~ to combine the constant values. As we discussed in Chapter 6, you can also suppress error reporting for a specific function using the @ operator. For example, to prevent errors from a call to mysql_connect( ), you can use:
$connection = @ mysql_connect("localhost","fred","shhh");
We recommend that during development you turn on all error reporting using the global php.ini setting. Change it to:
error_reporting = E_ALL
However, we don't recommend this setting for deployment for the reasons we discussed previously. When you deploy your application, you can follow two approaches to handling errors: turn them off?a very optimistic approach!?or write a handler that tries to deal with them gracefully during the application's run. Turning them off is easy (set the php.ini setting error_reporting = 0) but it isn't recommended because it'll prevent any problems with your application being detected. Adding a professional error handler to your application is discussed later in Section 12.3.