Debugging
Workshop Requirements
Before beginning this workshop ensure that you have the ability to upload
PHP files to a PHP enabled webserver that has a MySQL database server also.
You should also have a rudimentary understanding of PHP and MySQL. If you
do not then you can complete the following Virtual Workshops:
You should also have some experience with HTML programming.
Introduction
In the other workshops in this series so far we have concentrated on producing
functions to achieve certain results. This workshop is slightly different,
more of a reference for what to do when things go wrong (and they will!).
This is aimed at novice programmers, as those with experience in other languages
will know the principles involved already.
Getting Started
To begin, let's create PHP file with the following code.
<html>
<head><title>Debug Example</title></head>
<body>
<?
echo "<h2>Debugging Workshop</h2>";
echo "<p>We are practicing how to fix various errors</p>";
?>
</body>
</html>
First test that the script works, and next we are going to deliberately break
things.
Errors of Omission
PHP is quite good at giving error messages, but for new developers the fact
that an error has occurred in the first instance can be quite daunting.
Missing Semi-Colon
The PHP parser requires that we use a semi-colon at the end of each PHP statement,
otherwise it gets confused. To look at this type of error remove the semicolon
from the first line of PHP code.
echo "<h2>Debugging Workshop</h2>"
echo "<p>We are practicing how to fix various errors</p>";
Which will result in the following error.
Parse error: parse error, unexpected T_ECHO, expecting ',' or ';' in /path/to/debug.php on line 6
Which does actually tell us quite a lot:
1) There has been a parse error: The PHP interpreter has
come across an error and doesn't know what it is supposed to do, so just stops.
2) It wasn't expecting another echo (T_ECHO) statement,
as it hadn't finished the first one. If the next line after the missing semi-colon
was an if statement or a while statement
etc then these two would be unexpected (T_IF and T_WHILE etc).
3) What the interpreter was expecting was a ' , ' or a '
; ' - which we know is what was missing.
4) Which file this was in i.e. '/path/to/debug.php' - useful
if you have included functions from different files.
5) Which line the PHP interpreter finds a semi-colon in - which is actually
the next line - but does act as an indicator in the script as to where the
problem lies.
We can fix this by replacing the semi-colon again.
Missing half of a pair
As we know, PHP uses a series of paired characters to control what happens
in the script.
- "Quotation Marks" - used to
encapsulate values
- (Brackets) - used to signify a comparison
to be made
- {Braces} or {Curly
Brackets}- used to contain code to be executed as part
of a conditional statement or function.
- The '<%' and '%>' tags that open
and close parts of the file that are to be considered PHP code.
Let's have a look at each of these errors in turn.
Missing "Quotation Marks"
echo "<h2>Debugging Workshop</h2>;
echo "<p>We are practicing how to fix various errors</p>";
Parse error: parse error, unexpected '>' in /path/to/debug.php on line 6
This time the parse error occurs because the " is closed after the second
echo statement and the PHP interpreter encounters non PHP code (HTML) that
it doesn't know what to do with.
Missing (Brackets)
If we add an if condition to test for the presence of the
'Submit' variable passed to the scripts (as in part 4
- Introducing Functions) we can omit the closing bracket of the condition
and see the error that generates.
echo "<h2>Debugging Workshop</h2>";
if (!$_REQUEST['Submit'] {
echo "<p>We are practicing how to fix various errors</p";
}
Parse error: parse error, unexpected T_ECHO in /path/to/debug.php on line 7
As we can see this is a similar error: the interpreter finds the echo()
function before the condition has been ended by a bracket and knows there
has been an error.
Missing {Braces}
This is slightly trickier as there can be lots of nested functions and conditions,
which can lead to the problem being more difficult to track down. Let's add
a while loop to illustrate (test the output just to make
sure that it works).
<?
echo "<h2>Debugging Workshop</h2>";
$count = 1;
while ($count <= 5) {
if (!$_REQUEST['Submit']) {
echo "<p>We are practicing how to fix various errors</p>";
}
$count += 1;
}
We can remove the closing Brace from the if statement:
echo "<h2>Debugging Workshop</h2>";
$count = 1;
while ($count <= 5) {
if (!$_REQUEST['Submit']) {
echo "<p>We are practicing how to fix various errors</p>";
$count += 1;
}
Or the while statement:
echo "<h2>Debugging Workshop</h2>";
$count = 1;
while ($count <= 5) {
if (!$_REQUEST['Submit']) {
echo "<p>We are practicing how to fix various errors</p>";
}
$count += 1;
We end up with the same error message.
Parse error: parse error, unexpected $ in /path/to/debug.php on line 15
This can obviously make debugging a bit more difficult. There are several
solutions to overcome this problem.
- Preventative
- Use an editor that highlights the matching pair when one or other is
selected (like Notepad++)
allowing you to see mismatched pairs.
- Put a comment after each closing brace to indicate which condition is
closed (I find this rather tedious).
- Reactive
- Comment out the nested conditions until the code works as intended then
uncomment pairs until you discover the problem.
- You can print out the code and score off matching pairs until you again
discover the problem
Missing '?>' tags
Delete the closing PHP tag:
<?
echo "<h2>Debugging Workshop</h2>";
$count = 1;
while ($count <= 5) {
if (!$_REQUEST['Submit']) {
echo "<p>We are practicing how to fix various errors</p>";
}
$count += 1;
}
And we see this error:
Parse error: parse error, unexpected '/' in /path/to/debug.php on line 14
Which is simliar to omitting a closing quotation mark as the PHP interpreter
isn't expecting the pure HTML and doesn't know what to do with it.
Problems with Variables
Most problems with variables come from them being misspelled, but there is
no error warning to tell us what is wrong when this happens. What usually
happens is that 'nothing' happens when we expected something. Consider this
example:
<body>
<?
echo "<h2>Debugging Workshop</h2>";
$Message = "<p>We are practicing how to fix various errors</p>";
echo $message;
?>
</body>
The text "We are practicing how to fix various errors"
will never be displayed as we have assigned the text to a variable called
$Message (with an uppercase M) but echoed the variable $message (lowercase
m) which is empty. It is important to ensure that the variable you assign
a value to is exactly the same when used later in your script.
Form Problems
Similar problems can happen when using HTML forms and PHP built in super
arrays $_GET, $_POST or $_REQUEST. A form field named message could be named
with a lower case m.
<input name="message" type="text" />
But called within the script using an uppercase M.
echo $_REQUEST['Message'};
Which would fail also.
'=' Vs '=='
A common use for a variable is as a control for a matching condition and
depending if the condition is met or not execute different code (such as we
used in earlier workshops for the value of the submit button). To explain
let's put the following into our debug.php file.
<body>
<?
echo "<h2>Debugging Workshop</h2>";
$chkvar = "true";
if ($chkvar = "false") {
echo"<p>We are practicing how to fix various errors</p>";
}
?>
</body>
If we run this script the message will be displayed even though the condition
has not been met ($chkvar being false). This is because we have not checked
the value of $chkvar, simply successfully reassigned the value of the variable.
This is why the if condition returns a positive result and
displays the message. If we change the operator in the if
condition to the correct comparison operator (==) rather than the assignment
operator (=) the script will fail to display the message.
<body>
<?
echo "<h2>Debugging Workshop</h2>";
$chkvar = "true";
if ($chkvar == "false") {
echo"<p>We are practicing how to fix various errors</p>";
}
?>
</body>
We can double check this by changing the value of the variable to 'false'.
$chkvar = "false";
Using debug code
In complicated scripts it can be difficult to see where a problem is occurring
and thus it is a good idea to include debug code. This may be to see the values
of variables used in conditions or even just testing that a control loop has
been executed. Place the following into the debug.php file.
<body>
<?
echo "<h2>Debugging Workshop</h2>";
$chkvar = "true";
while ($chkvar == "false") {
if ($count < 5) {
echo "<p>We are practicing how to fix various errors</p>";
} else {
$chkvar = "true";
}
$Count += 1;
}
?>
</body>
This will fail to print the text "We are practicing how to fix various
errors". When attempting to correct this we notice that there are
two nested conditions which must be met and thus we can introduce debug code
to test which one (or both) is failing. To test if the while
condition is being met we can echo any text we like between the while
and the if statements: I tend to use my name.
$chkvar = "true";
while ($chkvar == "false") {
echo "keith";
if ($count < 5) {
Testing the debug script will fail to echo 'keith' and thus we know there
is a problem with the while condition being met. This is
because we have set the starting value of $chkvar to 'true' rather than 'false'.
Correct this and the script will indeed echo keith, but (along with the text
we want) far to many times. This signifies that there is something wrong with
the if statement as well. It appears that the $chkvar variable
is never being assigned the value true so that the while
loop stops. As this relies on the $count variable reaching 5 there is something
not working properly. We can comment out our first piece of debug code and
place another that echoes the value of the variable being evaluated - $count:
while ($chkvar == "false") {
//echo "keith";
if ($count < 5) {
echo "<p>We are practicing how to fix various errors</p>";
echo $count;
} else {
$chkvar = "true";
}
$Count += 1;
We can see from our test this time that $count is missing and it can be surmised
that it has no value. Thus we know it is likely that there is a mismatch between
when the $count variable is tested for and when it being assigned. A look
at the code used to increase the value of the count variable sees that we
have mistakenly used an uppercase C. Changing this to a lowercase c will make
the script work as planned.
MySQL debug code
Although we have comprehensively covered how to use error checking code to
give useful error messages back to the user, we have missed out one important
piece of debug code that is vital to the developer.... displaying the SQL
statement if there is an error with its execution. This hasn't been necessary
in other workshops as the SQL statements are correct. If we look at error
checking code we've used before:
$sql = "SELECT * FRO table";
$result = @mysql_query($sql, $conn);
if (!$result) {
echo("<p>Error performing query: " . mysql_error() . "</p>");
exit();
}
We can see that if the SQL statement fails (there is no result) then we print
the error message. Something like:
Error performing query: You have an error in your SQL syntax near 'FRO table' at line 1
If would also be useful to echo the offending SQL statement.
if (!$result) {
echo("<p>Error performing query: " . mysql_error() . "</p>");
echo $sql;
exit();
}
Which would produce an output of:
Error performing query: You have an error in your SQL syntax near 'FRO table' at line 1
Query: SELECT * FRO table;
And we can see that there has been a 'M' missed off the end of FROM in the
statement.
Conclusion
When writing your own scripts you may come across more specific problems
than this workshop covers. As usual the PHP
manual is the best place to look for help and hopefully this Workshop
will at least help you identify where the problem lies.
|