What is debugging?
Debugging essentially means to track down an error in your code. Found a "bug" in your code? Then you need to "de-bug" it
This article will introduce you to some basic concepts such as error checking and built-in functions like var_dump() that will aid you in tracking down errors in your PHP applications. There are also many fully-fledged debugging tools for PHP that lets you set breakpoints, watch variables, and such like, but we won't be using them in this article
Number One Rule: Always Check
This is my number one rule when writing applications. Whenever your code does something that can potentially fail, you should always add a check to your code to see if it did fail.
For example, in the following code, we take the URL parameter 'name' and use it to display a personal greeting to our visitor:
PHP Code:
<?php
$name = $_GET['name'];
echo 'Hello ' . $name . ', welcome to our website!';
Code:
http://www.example.com/myScript.php?name=Alan
Code:
Hello Alan, welcome to our website!
However, what happens if we don't specify a name? We would then end up with something like:
Code:
Hello , welcome to our website!
To solve this problem, we need to perform a check to see if the name has been supplied. Lets edit our script so that it looks like the following:
PHP Code:
<?php
if ($_GET['name'])
{
$name = $_GET['name'];
}
else
{
$name = 'Visitor';
}
echo 'Hello ' . $name . ', welcome to our website!';
Now if we run our script without supplying a name, the following would appear:
Code:
Hello Visitor, welcome to our website!
As a second example, we will use MySQL to fetch the top 5 articles from a table then display their titles. Take a look at the following code:
PHP Code:
<?php
// Connect to our database and select the 'myDatabase' database
$db = mysql_connect('localhost', 'username', 'password');
mysql_query('USE myDatabase');
// Fetch the top 5 article ids and titles from our rating table
$top5_q = "SELECT id, title, MAX(rating) FROM rating ORDER BY articles DESC LIMIT 5";
$top5_r = mysql_query($top5_q);
// Loop through our results...
while ($top5_a = mysql_fetch_array($top5_r))
{
// ...and echo each articles title
echo $top5_a['title'] . '<br />';
}
This is why checking that a function was successful is so important, in our code above we have a bug but due to the lack of checks, we have no idea where it could be.
Now, lets add in some checks so we can find out where the problem is occurring.
First off all, we need to check that we even connected to the database server. If that didn't happen, the rest of the code will fail.
PHP Code:
<?php
// Connect to our database and select he 'myDatabase' database
$db = mysql_connect('localhost', 'username', 'password');
// Check that we connected ok...
if (!db)
{
// ...Nope! Display the MySQL error
die('Could not connect to the database: ' . mysql_error());
}
The mysql_error() function will display the error text returned from the MySQL server which will be a great help in finding out why your mysql_connect() failed.
If we run our script now, we find that it still runs but without errors or our article titles so lets move on to the next block of code.
PHP Code:
mysql_query('USE myDatabase') or die(mysql_error());
This time, we are saying "Run the query using the mysql_query function and if it fails, run the die() function which calls mysql_error()". The " or die();" trick can be very handy in tracking down bugs in your applications as it provides a quick way to print an error in the event that your function fails.
Now, we run our code again and still get no errors, so all is well with that bit of code. On to the next block of code.
PHP Code:
// Fetch the top 5 article ids and titles from our rating table
$top5_q = "SELECT id, title FROM rating ORDER BY articles DESC LIMIT 5";
$top5_r = mysql_query($top5_q);
// Check to see that we got a result
if (!$top5_r)
{
// No result, display an error!
die('Error in query: ' . mysql_error());
}
If we run our script again now we get an error!
Code:
Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
Hopefully you can now see the importance of good error checking in your applications. Although it may seem like a lot of extra work and code, it will pay off in the long term. In our script above we where lucky that our bug revealed itself only a few rows down. In larger scripts a bug may not reveal itself until hundreds, or even thousands of lines of code later leaving you with an impossible task when trying to find it.
Useful Functions
You have already seen two of the useful functions when debugging, die() and mysql_error() (note: most database libraries in PHP have their own _error() function that you can use).
Another two useful functions are called var_dump() and print_r().
var_dump() does what it says on the tin. It will "dump" a variable (and it's details) to the screen.
For example:
PHP Code:
<?php
$var1 = 'Hello, World!';
$var2 = 26;
var_dump($var1);
var_dump($var2);
var_dump($var3);
Code:
string(13) "Hello, World!" int(26) NULL
var_dump() can be useful in determining whether a variable has been set and whether it contains the information you where expecting.
The print_r function will recursively print an array. For example:
PHP Code:
<?php
$myArray = array('firstname' => 'Alan',
'surname' => 'Wagstaff',
'email' => 'alan@example.com',
'phone' => '12345-678901');
print_r($myArray);
Code:
Array
(
[firstname] => Alan
[surname] => Wagstaff
[email] => alan@example.com
[phone] => 12345-678901
)
Error Reporting and Logging
When writing and debugging our application, we will always want to display all notices, warnings and errors. Error messages hidden in a log file are not much good to us when debugging
The first thing we need to check is that we are set to display errors. You can do this by opening your PHP.INI and checking that "display_errors" is set to "On".
Next, at the top of our script we want to add:
PHP Code:
error_reporting(E_ALL);
Conclusion
As you have seen, proper error checking in your applications will save vast amounts of time when debugging later. I hope that you have seen the importance of error checking and that to effectively debug an application it is a case of either starting from the top and working down until you find the bug, or starting from the error and working back up until you find the bug. Thankfully we have functions such as mysql_error() and var_dump() to help us in this task.
Refereces and Further Reading
PHP: die - Manual
PHP: mysql_error - Manual
PHP: var_dump - Manual
PHP: print_r - Manual
PHP: error_reporting - Manual


Join the friendly bunch on IRC...