DekGenius.com
Previous Section  < Day Day Up >  Next Section

12.3 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. Example 12-3 shows a program that incorrectly attempts to calculate the total cost of a few items.

Example 12-3. A broken program without debugging output
$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);

Example 12-3 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 Example 12-3? 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. Example 12-4 annotates Example 12-3 with some diagnostic print statements.

Example 12-4. A broken program with debugging output
$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);

Example 12-4 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 from Example 12-4, 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 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. Example 12-5 prints the contents of all submitted form parameters with var_dump( ).

Editing the Right File

If you make changes to a program while debugging it but don't see those changes reflected when you reload the program in your web browser, make sure you're editing the right file. When working with a local copy of the program but loading it in the browser from a remote server, be sure to copy the changed file to the server before you reload the page.

One way to make sure that the file you're editing and the page you're looking at in the web browser are in sync is to temporarily add a line at the top of the program that calls die( ), as in the following.

die('This is: ' . _ _FILE_ _);

The special constant _ _FILE_ _ holds the name of the file being run. So when you load a PHP page in your browser with a URL such as http://www.example.com/catalog.php, that has the code shown above at the top, all you should see is something like:

This is: /usr/local/htdocs/catalog.php

When you see the results of die( ) in your web browser, you know you're editing the right file. Remove the call to die( ) from your program and continue debugging.


Example 12-5. Printing all submitted form parameters with var_dump( )
print '<pre>'; var_dump($_POST); print '</pre>';

Debugging messages are informative but can be confusing or disruptive when mixed in with the regular page output. To send debugging messages to the web server error log instead of the web browser, use the error_log( ) function instead of print. Example 12-6 shows the program from Example 12-4 but uses error_log( ) to send the diagnostic messages to the web server error log.

Example 12-6. A broken program with error log debugging output
$prices = array(5.95, 3.00, 12.50);
$total_price = 0;
$tax_rate = 1.08; // 8% tax

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

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

Example 12-6 prints just the total price line:

Total price (with tax): $13.50

However, it sends lines to the web server error log that look like this:

[Wed Oct 20 16:33:02 2004] [error] [before: 0]
[Wed Oct 20 16:33:02 2004] [error] [after: 6.426]
[Wed Oct 20 16:33:02 2004] [error] [before: 6.426]
[Wed Oct 20 16:33:02 2004] [error] [after: 3.24]
[Wed Oct 20 16:33:02 2004] [error] [before: 3.24]
[Wed Oct 20 16:33:02 2004] [error] [after: 13.5]

The exact location of your web server error log varies based on how your web server is configured. If you're using Apache, the error log location is specified by the ErrorLog Apache configuration setting.

Because the var_dump( ) function itself prints information, you need to do a little fancy footwork to send its output to the error log, similar to the output buffering functionality discussed at the end of Section 8.6. You surround the call to var_dump( ) with functions that temporarily suspend output, as shown in Example 12-7.

Example 12-7. Sending all submitted form parameters to the error log with var_dump( )
// Capture output instead of printing it
ob_start( );
// Call var_dump( ) as usual
var_dump($_POST);
// Store in $output the output generated since calling ob_start( ) 
$output = ob_get_contents( );
// Go back to regular printing of output
ob_end_clean( );
// Send $output to the error log
error_log($output);

The ob_start( ), ob_get_contents( ), and ob_end_clean( ) functions in Example 12-7 manipulate how the PHP interpreter generates output. The ob_start( ) function tells the interpreter "Don't print anything from now on. Just accumulate anything you would print in an internal buffer." When var_dump( ) is called, the interpreter is under the spell of ob_start( ), so the output goes into that internal buffer. The ob_get_contents( ) function returns the contents of the internal buffer. Since var_dump( ) is the only thing that generated output since ob_start( ) was called, this puts the output of var_dump( ) into $output. The ob_end_clean( ) function undoes the work of ob_start( ): it tells the PHP interpreter to go back to its regular behavior with regard to printing. Last, error_log( ) sends $output (which holds what var_dump( ) "printed") to the web server error log.

    Previous Section  < Day Day Up >  Next Section