Introduction
Everyday the forums see
probably hundreds of topics posted where the problem is a fairly simple
error. These generally fall in 4 categories:
- Syntactical/parse errors
- Fatal errors, warnings and notices
- Database errors
- Logical errors
As a beginner, it can be difficult to find and solve these errors. By
tackling each of these in turn, I hope to teach you some methods of
finding and solving them. So we'll get started with syntactical errors
first.
Syntax Errors
Syntax errors. Eugh. We've all been there -- a nasty error message and we don't know what it means.
However, sometimes people don't even get as far as seeing the error
message: they have PHP setup so that it won't display them. Handy for a
live site; but rubbish for something in development. So turn them on!
Either do this through your php.ini file (you're looking for the
display_errors setting) or through the ini_set function. You can add
this to the top of your code:
<?php
ini_set('display_errors','On');
?>
Note:
Unfortunately, if your error is syntactical, then you'll need to make
this change to your php.ini. If PHP can't parse the page correctly,
then the change to the setting won't be made. (with thanks to
philipolson for mentioning this)
This is often the cause of the 'My page shows nothing!' problem,
which is seen so often on the forum. That is, there's a syntax error,
but it's not being displayed.
Right, now that we're not flying blind and we're actually going to see our errors, we can move onto fixing them.
Syntax Errors -- Debugging
Computers are stupid. You can
quite easily understand something with a missing piece of punctuation,
but computers? They throw their teddies out the pram. You might, for
instance, see this:
Parse error: syntax error, unexpected T_VARIABLE in C:\wamp\www\phpfreaks.php on line 3
Now, when something's unexpected, it means just that. However, it
does not always mean that it's not required. For example, the above
error message was generated with this code:
<?php
$foo ='foo'
$bar = 'bar';
?>
The unexpected element of the above is $bar. But we wanted to define $bar, that's not unexpected. What is unexpected is the lack of semi-colon on the previous line. This leads us to one important aspect of finding and fixing errors: check the previous lines.
Other common causes of syntax errors are:
- Unclosed quotes
- Missing or Extra parentheses (for example, with if statements)
- Unclosed braces -- more on this later
One thing that
will help you avoid making syntax errors is the use of a good editor
with syntax highlighting. This will make things such as unclosed quotes
very obvious. I'd personally recommend PHP Designer or Eclipse, but
other people will suggest different editors. There's a long thread here dedicated to the debate.
That's a wrap on syntax errors so we'll move onto fatal errors, warnings and notices.
Fatal Errors, Warnings and Notices
Now would be a good time
to mention another common mistake: the use of error suppression during
development. PHP allows you to quietly ignore errors (other than
syntactical) by placing the @ symbol at the start of the line. As with
the display of errors, this is handy for a production server –- but
when you're trying to find out why something doesn't work, it's worse
than useless.
Fatal errors
Fatal errors are caused when PHP understands
what you've written, however what you're asking it to do can't be done.
Common examples include trying to use a function or class that hasn't
been defined. Fortunately, the error message generated should be nice
and obvious:
Fatal error: Call to undefined function foobar() in C:\wamp\www\phpfreaks.php on line 2
Warnings
Warnings refer to things which PHP can cope with,
but it's likely you didn't intend them. Common causes include trying to
include a missing file or using the incorrect number of parameters in a
function. Again, the error message should help you out.
Probably the most common warning sent is the one that looks something like this:
Warning: Cannot modify header information - headers already sent by (output started at C:\wamp\www\phpfreaks.php:2) in C:\wamp\www\phpfreaks.php on line 3
Or like this:
Warning: session_start() [function.session-start]: Cannot
send session cache limiter - headers already sent (output started at
C:\wamp\www\phpfreaks.php:2) in C:\wamp\www\phpfreaks.php on line 3
Both of these are caused by the same thing: you cannot change
headers -- which includes changing location or setting a cookie/session
-- after you have sent any content to the browser (ok smarty-pants so you can with output buffering, but that's a different subject for a different day).
Note: Output includes whitespace. So you can't even send a
space or blankline before you send a header. This catches people out
sometimes, particularly when including files. You might have some
whitespace after your closing PHP tag which is included in another file.
Notices
Finally, we have notices. So often ignored, but can
actually help you track an awful lot of errors. A notice is generally
given for something which is undefined: a variable, constant or element
of an array.
Before you see them, however, you'll need to make sure that PHP is
setup to report them. This requires a further change of your php.ini. I
recommend changing the error_reporting setting to E_ALL. This can also
be done at the top of your script with:
<?php
error_reporting(E_ALL);
?>
For more on error reporting and the relevant options, see the manual.
If you've just turned notices on, you may have just got a truckload
of error messages. PHP can cope with notices, hence why your script was
working before. But as mentioned, notices are incredibly useful for
tracking typos by warning you of an undeclared variable. Common notices
come from unquoted strings being used as the key of an array, such as:
<?php
$array = array('key'=>'value');
echo $array[key];
?>
This
is because, without quotes, key is a constant and not a string.
Whenever PHP encounters undefined constants, it assumes that it's a
string, so it can cope. However, best practice is to place quotes
around the key if it is a string.
Note: It's perfectly acceptable to use an unquoted string as your key inside double quotes, such as:
<?php
$array = array('key'=>'value');
echo "The array contains just one value: $array[key]";
?>
That about wraps it up for our first two types of error, so we'll move onto database errors.
Database Errors
How often have you seen this?
Warning: mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource in C:\wamp\www\phpfreaks.php on line 5
The error message doesn't tell you a lot, does it? What it does
tell you is that there was an error with your query. What we need is
way of seeing that error. Handily, mysql_error() does just that. Now,
you will see a lot of people on the forum (myself included) suggesting
that to test a query you should add an or die statement and echo
mysql_error() like so:
$result = mysql_query("SELECT * FROM tbl WHERE ...") or die(mysql_error());
However,
better practice would be to use "or trigger_error()". Why? Well,
because it will save you troubles should the script go live. By
throwing an error, you still get the benefit of seeing the problem
whilst you are developing and have display_errors turned on, but can
also handle things gracefully should the script go live and you turn
off error_reporting. You'll also want to echo your query. It's so much
easier to spot a syntax error when you actually look at what is being
executed. This is particularly true if the query is complex and
contains many variables.
Therefore, you should do this:
<?php
$sql = "SELECT * FROM tbl WHERE ...";
$result = mysql_query($sql) or trigger_error(mysql_error().'<br />Query was:'.$sql,E_USER_ERROR);
?>
Notice that we create our query in a string before we execute it; this allows us to echo it.
Now, you might also have a query which does not generate an error,
but also doesn't return what you expect. You may, for example, be
expecting lots of rows but don't get any. Again, the best thing you can
do is to echo the query:
<?php
$sql = "SELECT * FROM tbl WHERE ...";
$result = mysql_query($sql) or trigger_error(mysql_error().'<br />Query was:'.$sql,E_USER_ERROR);
echo '<br />'.Query was:'.$sql.'<br />';
?>
9
times out of 10 you will find that a variable in your query doesn't
contain what you expected it to and so can trace the error.
Finally, we'll talk a little bit about logical errors on the next page.
Logical Errors
So your script doesn't report any errors and
the queries are working fine. But it doesn't do what it's supposed to.
Chances are, you have an error in your logic.
Unfortunately, logical errors are the hardest to find. You may have
been expecting an if statement to be true, when indeed it is false. The
best solution to any problem like this is: echo, echo, echo. You must
echo out information at strategic places throughout your script to help
you narrow down the problem. You might, for example, check that a
function has been called by placing an echo inside it. You might echo a
variable to check its value; or you might echo something after an if
statement to see if it was true or false. Never assume anything. You
might have missed something and your best bet is to be patient and
track it down.
Logical errors are also often caused by poor code layout. Always
indent code between braces. Again, a good editor will help you out, as
it will do this for you. It's much easier to keep track of braces and
spot missing ones if you properly indent your code. It should also
allow you to highlight one brace and find it's partner. The worst error
message you can see is this:
Parse error: syntax error, unexpected $end in C:\wamp\www\phpfreaks.php on line 3
This usually means there's an unclosed brace. I've seen plenty of
people assume they can just tack a brace onto the end of the script.
It's almost never that simple. If I see someone with this problem,
they're on their own! Your only option is to carefully walk though your
code and make sure every brace is opened and closed in the correct
place.
This error would also be generated if you had an unclosed backtick
(`). Thanks to 448191 for pointing out that a lot of editors don't pick
this up in their highlighting, so it could be tricky to spot.
That's it for logical errors and the whole tutorial. Just sit tight through the summary and you'll be off.
Tutorial Summary
In no particular order, here are my tips for finding your errors:
- Make sure PHP is displaying errors
- Set your error reporting to E_ALL
- Remove error suppression
- Use a good editor
- Indent your code
- Use 'or trigger_error' statements with every query
- Echo out if you're having problems
- Check the previous lines for syntax errors
I should
also say that my intention with this tutorial was to provide some
general help for a beginner during the development stage. You should
note that there are other, more graceful methods of handling errors (an
error handling class with exceptions being the best route) in the long
run. Even if you don't go the whole hog you should consider the
following before your site goes live:
- Turning off display errors. Yeah, I know I told you to turn it on
earlier, but that was to help you find the error to start with. Once
your site is live, you don't want users seeing nasty error messages.
- Ensuring log_errors is turned on. This allows you to find out if any errors do occur after your site is live.
- Think about your error_reporting level. In PHP 6, E_STRICT errors will become apart of E_ALL. For more on this, see the manual.