PHP debugging is an art-form. Here are some common tricks of the trade.
Indent your code properly
If you do not properly indent your code so that you can visually see the hierarchical relationships in it, you will never be able to successfully debug it. Furthermore, you will never become a successful developer. It’s that simple (almost). This applies to all XHTML, CSS, Javascript, and PHP code you will ever write.
Before you do anything else, indent your code. You will be amazed at how many errors you will see immediately.
The rule: Something that is “inside of” something else should be indented one level to the right. For example:
function doSomething($indented) {
$futureSuccess = false;
if ($indented) {
$futureSuccess = true;
}
return $futureSuccess;
}
Notice that all code “within” the function is indented to the right, relative to the opening and closing of the function. Further note that the code within the “if statement” is also indented one more level to the right. This makes the code easy to read, and so stupid errors, such as missing brackets, become easier to spot.
Foreach statement errors
If you encounter an error that looks like this, the problem is simple:
Let’s say your foreach statement looks like this:
foreach ($someArray as $someElement) {
///some stuff here
}
The error: This error is telling you that the variable $someArray is not actually an array. Don’t argue… PHP is always right about this.
The solution: make sure the variable you think is an array really is an array. You can see the contents of the array by printing out the raw contents of the array using the print_r() function like this:
print_r($someArray); //dump out the raw data in the array
foreach ($someArray as $someElement) {
///some stuff here
}
Hint: you can make sure your array is aways an array by declaring it as an array before you start using it.
$someArray = array(); //set the variable to a blank array
//do some stuff to put data into the array here
foreach ($someArray as $someElement) {
///some stuff here
}
This hint is especially useful if you are populating the array with data pulled from a database. For example, let’s say that you are running a query to load all of the comments for a blog post and put them into an array called $comments:
$result = mysql_query($myQuery); //run the query
while($row = mysql_fetch_array($result)) {
$comments[] = $row; //put the current row into the comments array
}
If, as is perfectly common, the blog post in question does not have any comments associated with it, the while loop will never loop, because there are no rows in the result variable. This means the $comments array will never have any data put into it, which is fine since there are no comments.
But if you later try to loop through all the elements in the comments array like this:
foreach ($comments as $comment) {
//do something
}
You will get this error because you have not said that $comments = array(); So make sure you always specify that an array is an array:
$comments = array(); //make this variable a blank array
$result = mysql_query($myQuery); //run the query
while($row = mysql_fetch_array($result)) {
$comments[] = $row; //put the current row into the comments array
}
Unexpected $end error
You will most likely come upon this error at some point:
This is equally simple. It means that you are missing an ending bracket on some block of code. For example:
while ($something == true) {
//do something
The error: If you do not have a closing “}” at the end of the while loop, it will cause this error. The same is true for closing brackets on any kind of block statement, like for loops, if statements, while loops, switch statements, function definitions, class definitions, etc. Anywhere you have an opening bracket, you must eventually have a closing bracket:
while ($something == true) {
//do something
}
Hint: By the way, this same error is produced if you are missing a closing heredoc tag, or if the heredoc tag is not all alone on a line with no spaces before or after it. Here is an example of a heredoc tag with some spaces on the same line as the END; tag: this will produce the error. The END; tag must be the only thing on the last line.
print <<<END
this is some text I want to print to the page
END;
Can’t connect to local MySQL server
If you see an error that looks like this, it means that your script did not successfully connect to the database:
First debugging step: First, make sure you are including the script that has all the database information in it at the top of your script:
//require database connection info
require_once("dbinfo/db.php");
Second debugging step: Make sure the db.php file has the correct username, password, hostname, and database name in it.
$dbServer = "mysql.fakedomain.com"; $dbUser = "amos"; $dbPass = "noneofyourbusiness!"; $dbName = "exampledb";
Third debugging step: Make sure that you are connecting to the database at the top of your script, and disconnecting at the bottom:
//require database connection info
require_once("dbinfo/db.php");
//connect to database
$cxn = @ConnectToDb($dbServer, $dbUser, $dbPass, $dbName);
//do something interesting
//disconnect from database
$cxn = @DisconnectFromDb($dbServer, $dbUser, $dbPass, $dbName);
MySQL query not working as expected
It happens every class that someone has a problem where the data they were expecting to store in the database does not seem to be getting stored there. Or the rows they were trying to read with a SELECT statement are not getting read. MySQL queries are extremely simple things to debug.
Let’s say you have a query statement like this, but it’s not working.
$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
$result = mysql_query($result);
Before you start: Before you even bother debugging, you should have phpMyAdmin open in a browser tab so that you can easily browse the contents of the table you are trying to insert data into. Clicking the “Browse” tab in the “table view” for the table you are dealing with is easiest way of checking to see if data is getting stored in your table.
First MySQL debugging step: First, you want to make sure that the command to query the database is actually getting executed the way you think it is. Maybe the variables you are using, $title, and $body do not have what you think they have inside them. So add a little echo statement that outputs the query you are trying to run.
$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
echo $myQuery;
$result = mysql_query($result);
You will be surprised at how often this simple echo statement will show you the problem. For example, if this code outputs something like the following:
INSERT into abloomberg_posts (user_id, title, body) VALUES (, '', 'this is the body')
That would indicate that the $userId and $title variables do not have anything in them, which is why they are showing up blank when you echo the query.
Second MySQL debugging step: the second easiest debugging step is to output any errors that MySQL is encountering. These won’t be output by defuault, so you must specify that you are interested in seeing them. Use the mysql_error() function after you run the query:
$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
$result = mysql_query($result);
echo mysql_error(); //output any MySQL errors
If this produces an error on the page, it will indicate if your MySQL query syntax has something wrong with it. Check the syntax of the query you are running by echoing it as we did in the first step, and make sure it looks correct:
$myQuery = "INSERT into abloomberg_posts (user_id, title, body) VALUES ({$userId}, '{$title}', '{$body}')";
echo $myQuery . "<br />"; //echo the query to the page
$result = mysql_query($result);
echo mysql_error() . "<br />"; //output any MySQL errors
Create a custom error handler
It is possible to handle errors in a customized way. I do not recommend you do this in PHP, but I’m including it here to be thorough about the topic. Feel free to skip the rest of this blog post.
You can choose to ignore some errors and respond to others as you see fit. To do so, you will need to create an error handler. This is conceptually similar to how we created event handlers in Javascript to respond to onclick events, etc.
First of all, you must specify which errors you want to see using PHP’s built-in error_reporting() function. You can see the full list of possible errors on the PHP reference page for this function. Here are the most common ones you’ll be interested in:
error_reporting(E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE);
Then you specify which function gets called when an error of any of those types is encountered using the set_error_handler() function. This function takes one parameter: the name of the function that gets automatically called when an error occurs.
$errhandle = set_error_handler("myErrorHandler");
And of course, this means you must also define the function, in this case “myErrorHandler” that you specified just now. When an error occurs, this function will get called and automatically passed four parameters: the “error number”, the error message, the file that caused the error, and the line number in the code that produced the error. Here is a simple error handler that just detects which type of error occured, and outputs some text for each of them:
function myErrorHandler($errno, $errstr, $errfile, $errline) {
switch ($errno) {
case E_USER_ERROR:
echo "<b>My ERROR</b> [$errno] $errstr<br />n";
echo " Fatal error in line $errline of file $errfile";
echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />n";
echo "Aborting...<br />n";
exit(1);
break;
case E_USER_WARNING:
echo "<b>My WARNING</b> [$errno] $errstr<br />n";
break;
case E_USER_NOTICE:
echo "<b>My NOTICE</b> [$errno] $errstr<br />n";
break;
default:
echo "Unkown error type: [$errno] $errstr<br />n";
break;
}
}
Suppressing errors
As an alternative, if you just wanted to suppress all errors, you could make a function like this instead:
function myErrorHandler($errno, $errstr, $errfile, $errline) {
//suppress all errors
return true;
}
And you can probably see that if you wanted to handle some types of errors in a custom way and you wanted to suppress others, you would create a function like the first example handler above, but “return true;” for those types of errors that you wanted to suppress.