ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


PHP Debugging Basics

by David Sklar, author of Learning PHP 5
08/12/2004
Add Tag Clouds to Your Site

Whether you're a PHP newbie or a wizard, your programs are going to have bugs in them. Nobody's perfect. This article gives you some techniques for finding and fixing the problems in your programs. It covers three topics:

Configuring Error Reporting

First of all, you need to configure the PHP interpreter so that when an error happens, you can see information about it. The error info can be sent along with program output to the web browser. It can also be included in the web server error log. A common way to set things up is to have error output go to the web browser when you're debugging your program, and then to the web server error log once the program is finished and (supposedly) working properly. That way, web site users can't see any potentially sensitive data included with error output.

To make error messages display in the browser, set the display_errors configuration directive to On. To send errors to the web server error log, set log_errors to On. You can set them both to On if you want error messages in both places.

An error message that the PHP interpreter generates falls into one of five different categories:

You don't have to be notified about all of the different error categories. The error_reporting configuration directive controls which kinds of errors the PHP interpreter reports. The default value for error_reporting is E_ALL & ~E_NOTICE & ~E_STRICT, which tells the interpreter to report all errors except notices and strict notices.

PHP defines some constants you can use to set the value of error_reporting so that only errors of certain types get reported: E_ALL (for all errors except strict notices), E_PARSE (parse errors), E_ERROR (fatal errors), E_WARNING (warnings), E_NOTICE (notices), and E_STRICT (strict notices).

Because strict notices are rare (and new to PHP 5), they are not included in E_ALL. To tell the PHP interpreter that you want to hear about everything that could possibly be an error, set error_reporting to E_ALL | E_STRICT.

Fixing Parse Errors

The first time you write a PHP program, you discover that the PHP interpreter is extremely picky. If you leave out a necessary semicolon or start a string with a single quote but end it with a double quote, the interpreter doesn't run your program. It throws up its (virtual) hands, complains about a parse error, and leaves you stuck in the debugging wilderness.

This can be one of the most frustrating things about programming when you're getting started. Everything has to be phrased and punctuated just so in order for the PHP interpreter to accept it. One thing that helps this process along is writing your programs in an editor that is PHP-aware, such as BBEdit, Emacs, XEmacs, Komodo, Dreamweaver, PHPEd, PHPEdit, or Zend Studio.

These editors do syntax highlighting. This is a feature that changes the color of different parts of your program based on what those parts are. For example, strings are pink, keywords such as if and while are blue, comments are grey, and variables are black. Syntax highlighting makes it easier to detect things like a string that's missing its closing quote: the pink text continues past the line that the string is on, all the way to the end of the file (or to the next quote that appears later in the program).

Another feature of these editors is quote and bracket matching. This helps to make sure that your quotes and brackets are balanced. When you type a closing delimiter such as }, the editor highlights the opening { that it matches. Different editors do this in different ways, but typical methods are to flash the cursor at the location of the opening {, or bold the { } pair for a short time. This behavior is helpful for pairs of punctuation marks that go together: single and double quotes that delimit strings, parentheses, square brackets, and curly braces.

These editors also show the line numbers of your program files. When you get an error message from the PHP interpreter complaining about a parse error in line 35 in your program, you can focus on the right place to look for your error.

Parse errors happen when the PHP interpreter comes upon something unexpected in your program. Consider this broken program:

<?php
if $logged_in) {
        print "Welcome, user.";
    }
?>

When told to run that broken program, the PHP interpreter produces the following error message:

Parse error: parse error, unexpected T_VARIABLE, expecting '(' in welcome.php on line 2

That error message means that in line 2 of the file, the PHP interpreter was expecting to see an open parenthesis but instead, it encountered something called T_VARIABLE. That T_VARIABLE thing is called a token. It's the PHP interpreter's way of expressing different fundamental parts of programs. When the interpreter reads in a program, it translates what you've written into a list of tokens. Wherever you put a variable in your program, there is a T_VARIABLE token in the interpreter's list.

What the PHP interpreter is trying to tell you with the error message is "I was reading line 2 and saw a variable where I was expecting an open parenthesis." Looking at line 2 of the program, you can see why this is so: the open parenthesis that should start the if() test expression is missing. After seeing if, PHP expects a ( to start the test expression. Since that's not there, it sees $logged_in, a variable, instead.

A list of all of the tokens that the PHP interpreter uses (and therefore that may show up in an error message) is in the PHP online manual at www.php.net/tokens.

The insidious thing about parse errors, though, is that the line number in the error message is often not the line where the error actually is. The following program has such an error in it:

<?php
$first_name = "David';
if ($logged_in) {
    print "Welcome, $first_name";
} else {
    print "Howdy, Stranger.";
}
?>

When it tries to run this program, the PHP interpreter says:

Parse error: parse error, unexpected T_STRING in welcome.php on line 4

That error makes it seem like line 4 contains a string in a place where it shouldn't. But you can scrutinize line 4 all you want to find a problem with it, and you won't find one. That line, print "Welcome, $first_name"; is perfectly correct: the string is correctly delimited with double quotes and the line appropriately ends with a semicolon.

The real problem in the program is in line 2. The string being assigned to $first_name starts with a double quote but "ends" with a single quote. As the PHP interpreter reads line 2, it sees the double quote and thinks "OK, here comes a string. I'll read everything until the next (unescaped) double quote as the contents of this string." That makes the interpreter fly right over the single quote in line 2 and keep going all the way until the first double quote in line 4. When it sees that double quote, the interpreter thinks it's found the end of the string. It then considers what happens after the double quote to be a new command or statement. But what's after the double quote is Welcome, $first_name";. This doesn't make any sense to the interpreter. It's expecting a semicolon to end a statement, or maybe a . to concatenate the just-defined string with another string. But Welcome, $first_name"; is just an undelimited string sitting where it doesn't belong. So the interpreter gives up and shouts out a parse error.

Imagine you're running down the streets of Manhattan at supersonic speed. The sidewalk on 35th street has some cracks in it, so you trip. But you're going so fast that you land on 39th street and dirty the pavement with your blood and guts. Then a traffic safety officer comes over and says, "Hey! There's a problem with 39th street! Someone's soiled the sidewalk with their innards!"

That's what the PHP interpreter is doing, in this case. The line number in the parse error is where the interpreter sees something it doesn't expect, which is not always the line number where the actual error is.

When you get a parse error from the interpreter, first take a look at the line reported in the parse error. Check for the basics, such as making sure that you've got a semicolon at the end of the statement. If the line seems OK, work your way forward and back a few lines in the program to hunt down the actual error. Pay special attention to punctuation that goes in pairs: single or double quotes that delimit strings, parentheses in function calls or test expressions, square brackets in array elements, and curly braces in code blocks. Count that the number of opening punctuation marks (such as (, [, and {) matches the number of closing punctuation marks (such as ), ], and }).

Inspecting Program Data

Once you clear the parse error hurdle, you still may have some work to do before you reach the finish line. A program can be syntactically correct but logically flawed. Just as the sentence "The tugboat chewed apoplectically with six subtle buffaloes" is grammatically correct but meaningless nonsense, you can write a program that the PHP interpreter doesn't find any problems with, but doesn't do what you expect.

If your program is acting funny, add some checkpoints that display the values of variables. That way, you can see where the program's behavior diverges from your expectations. The following program incorrectly attempts to calculate the total cost of a few items:

<?php
$prices = array(5.95, 3.00, 12.50);
$total_price = 0;
$tax_rate = 1.08; // 8% tax

foreach ($prices as $price) {
    $total_price = $price * $tax_rate;
}

printf('Total price (with tax): $%.2f', $total_price);
?>

The program doesn't do the right thing. It prints:

Total price (with tax): $13.50

The total price of the items should be at least $20. What's wrong with the program? One way you can try to find out is to insert a line in the foreach() loop that prints the value of $total_price before and after it changes. That should provide some insight into why the math is wrong. Here's a version of the program with some diagnostic print statements:

<php
$prices = array(5.95, 3.00, 12.50);
$total_price = 0;
$tax_rate = 1.08; // 8% tax

foreach ($prices as $price) {
    print "[before: $total_price]";
    $total_price = $price * $tax_rate;
    print "[after: $total_price]";
}

printf('Total price (with tax): $%.2f', $total_price);
?>

This program prints:

[before: 0][after: 6.426][before: 6.426][after: 3.24][before: 3.24][after: 13.5]Total price (with tax): $13.50

From analyzing the debugging output, you can see that $total_price isn't increasing on each trip through the foreach() loop. Scrutinizing the code further leads you to the conclusion that the line:

$total_price = $price * tax_rate;

should be

$total_price += $price * tax_rate;

Instead of =, the assignment operator, the code needs +=, the increment-and-assign operator.

To include an array in debugging output, use var_dump(). It prints all of the elements in an array. Surround the output of var_dump() with HTML <pre></pre> tags to have it nicely formatted in your web browser. This line of code prints the contents of all submitted form parameters with var_dump():

print '<pre>'; var_dump($_POST); print '</pre>';

Going Further

Once you've got error reporting set up as you like it, and you know how to find parse errors, and you can inspect program data, you're on your way to a fruitful debugging career. However, a fully fleshed-out PHP programmer's toolbox consists of much more than just the tips in this article. Chapter 12 of Learning PHP 5, "Debugging," includes some additional debugging techniques. For more advanced debugging possibilities, check out PHP extensions such as XDebug and apd. Some of the PHP-aware editors listed in this article also include integrated debugging capabilities.

David Sklar is an independent consultant in New York City, the author of O'Reilly's Learning PHP 5, and a coauthor of PHP Cookbook.


In June 2004, O'Reilly Media, Inc., released Learning PHP 5.

Building Tag Clouds in Perl and PHP

Essential Reading

Building Tag Clouds in Perl and PHP
By Jim Bumgardner

Tag clouds are everywhere on the web these days. First popularized by the web sites Flickr, Technorati, and del.icio.us, these amorphous clumps of words now appear on a slew of web sites as visual evidence of their membership in the elite corps of "Web 2.0." This PDF analyzes what is and isn't a tag cloud, offers design tips for using them effectively, and then goes on to show how to collect tags and display them in the tag cloud format. Scripts are provided in Perl and PHP.

Yes, some have said tag clouds are a fad. But as you will see, tag clouds, when used properly, have real merits. More importantly, the skills you learn in making your own tag clouds enable you to make other interesting kinds of interfaces that will outlast the mercurial fads of this year or the next.


Read Online--Safari
Search this book on Safari:
 

Code Fragments only

Return to the PHP DevCenter

Copyright © 2009 O'Reilly Media, Inc.