Debugging was actually introduced in Chapter 1, when you learned to troubleshoot your installation of PHP. This chapter continues that discussion, and then takes a more detailed look at a formal debugging process.
After you've decided what your application or program should do, the process of building the program begins. You may be working with graphic artists building the pages that are rendered to the user (and this might be done in parallel with or before writing much code), and you also may be drawing diagrams or making outlines of the logical flow of your program. But at some point you'll write some code.
Typically, you'll write code and insert it into Web pages, as you've already done, or perhaps generate the HTML code for the Web pages via the echo statement or from with objects. Most likely, you'll write enough code to perform an understandable set of functions, and then bring up the pages in your browser to test it.
Testing is the first step in debugging. Obviously, if you haven't tested your code and found an error, there's nothing to debug yet. Quick little jobs whipping out a simple dynamic feature such as displaying the current date for a single page don't require a formal testing protocol; either the correct date appears or it doesn't. But more complex, full-featured applications require a higher level of testing, and a formal process for identifying and tracking the errors found. In this chapter we concentrate on just the testing required for debugging your code, but in a real production environment you'll encounter much more formal testing systems.
Values that Break Your Code
The first time you write the code for an application, it's tempting to assume the values you'll work with will fall neatly into the range of those you expected. But because PHP applications are designed to work with data submitted by users on the Internet, your application could instead receive values deliberately intended to break it (when your application fails or is hacked, it's broken).
Consequently, testing your code with unexpected values is a good part of any testing protocol. Before you examine the kinds of unexpected values your application might encounter in real use, consider data in Web applications.
All data submitted by a browser to your Web server is formatted as strings. For example, the number 1995 might be a year, or a price, but when it passes to the Web server via an HTTP request, it comes into the PHP processing engine as a string. Strings can be empty or contain any number of characters. If your program is expecting a number, that's okay, because PHP is very forgiving about data types. But if your program is expecting a string of a certain length and gets none, that could be a problem.
Even if the value received is numeric in nature (composed of all valid digit characters) so that it is properly turned into a number by PHP, the number could be too high or too low (outside the range of acceptable values), and that could also be a problem.
One of the first steps to take to protect your application is to define the ranges of values (whether string, number, date, or what-have-you) and then to test your application with values that fall outside these ranges (and don't forget to use empty or nil values as well as large and other strange values).
There can be other problems such as submitted values that fall into the appropriate range or data type, but are still bad in some way. For example, an e-mail address might be limited to 100 characters in your database, so what happens if a person submits an e-mail address that contains 101 characters? And what happens if someone forgets to include the @ in his e-mail address? The data submitted is still a string, and may look superficially like an e-mail address, but these kinds of errors can still cause problems.
So you may end up testing to make sure that the submitted string is actually formatted as a string, number, date, or whatever, and then proceeding to test whether it falls into the right range of values, and then performing more tests to make sure it is actually the right length and perhaps even that it contains some special characters pertinent to the kind of data it's supposed to be. Sounds like a lot of trouble, to be sure, but users are notorious for entering bad data and data that looks good but cannot be processed properly (such as "three" for "3"), so the extra time you spend testing now is definitely worthwhile.
Basic Error Types
As you write code, you test frequently at small milestones in your project, not after weeks of writing an entire application. It's very common for the first test to result in errors that PHP can catch programmatically. Syntax (or parse) errors, for example, occur when you leave out a semicolon or forget to close off a control-flow block with a curly brace. PHP provides some very descriptive error messages to help you find and fix these types of errors, and once you're familiar with the error messages, it's pretty easy to take care of the syntax errors.
An application's inability to find or open a file or connect to a database is another type of error that PHP catches. These errors are called runtime errors because they occur while the program is running. PHP still detects them programmatically and generates error messages for them.
Errors that PHP can catch and generate an error message for are often easy to find and fix, but sometimes error messages can be a little frustrating because they're, well, cryptic (like any programming language) until you get used to them. (PHP error messages are discussed in more depth later in the chapter.)
There's another significant type of error called a logic error, which occurs when your program has no syntax errors, runs fine, and produces an incorrect response or answer. Sometimes these are easy to find and debug; and other times they just drive you crazy because they may occur infrequently, or only under special conditions.
The most common syntax, runtime, and logic errors—and ways to debug them—are discussed throughout the rest of this chapter.
