Jump to content

PHP debugging techniques


boen_robot

Recommended Posts

(Based on earlier writings by "So Called" in this topic)1. Organization tips for all of programming 1.1. Start smallMake your big problems into little problems! Don't write 200 lines of code and then ask us why it doesn't work! Instead, write 10 or 20 lines of code and get that to work. Other things being equal, 20 lines of code will have 1/10 as many bugs as 200 lines of code. You are 10 times as likely to write good code if you write just a little not a lot, and 10 times more likely to have willing volunteers on the forum help you find out why it doesn't work. On a related note, don't write a whole mess of HTML, PHP and MySQL queries (even if it's well under 200 lines of code) and then ask yourself (or the forum) why it doesn't work. Write a few lines, test it, fix what's broke, then add more code. Don't add more complexity until you get what you've already written to work. This is the stage where you can expect help from an Internet forum. 1.2. Keep it readableSpeaking of creating a mess, avoid creating one by keeping your code readable. A lot of problems can be avoided or fixed quickly if you and other people can find their way around your code. You might have overlooked this as a "minor feature", but it's actually really important for this point - you can freely insert white space between different parts of your PHP code. This means you can (and should) insert white space wherever it makes logical sense. If you're not sure, err on the side of being with white space. For example, instead of

<?php$f=$_GET['f'];$l=$_GET['l'];$r=0;for($i=0;$i<100;$i++) if($i%2===0||$i%5===0)$r+=$i;echo "$f $l: $r";

make that

<?php$f = $_GET['f'];$l = $_GET['l']; $r = 0; for ($i = 0; $i < 100; $i++)	if ($i % 2 === 0 || $i % 5 === 0)		$r += $i; echo "$f $l: $r";

Also, use meaningful variable names that tell you what a variable is used for. For example, instead of the above, have it as

<?php$firstName = $_GET['firstName'];$lastName = $_GET['lastName']; $result = 0; for ($i = 0; $i < 100; $i++)	if ($i % 2 === 0 || $i % 5 === 0)		$result += $i; echo "$firstName $lastName: $result";

And finally, if brackets/braces/whatever are allowed, but optional, use them anyway, to clearly define the intended boundaries, e.g.:

<?php$firstName = $_GET['firstName'];$lastName = $_GET['lastName']; $result = 0; for ($i = 0; $i < 100; $i++) {	if (($i % 2 === 0) || ($i % 5 === 0)) {		$result += $i;	}} echo "{$firstName} {$lastName}: {$result}";

If you search the web, you'll find different advises on how much and where should white spaces and brackets/braces be (e.g. some programmers prefer the opening bracket on a new line, while others prefer it on the same line as the statement - as above). No style is truly "better" than another. Whatever feels readable to you, use that. However, it's important to note: Whatever your preference is, be consistent. Don't use one style at one place, and another style at another place, as this makes your code harder to read.(Also worth noting: Some PHP editors allow you, with the click of a button, to automatically add white spaces according to predefined rules, so that at least the first part of what we did above is automated) 1.3. Probe your codeAsking for help on the forum may get you help in hours, days or sometimes weeks. But ask your code the same questions and you may get answers in seconds or (at worst) minutes! The remainder of this topic will address how you can ask your code to tell you why it won't work. These things are not "fixes", they're means to finding a fix (which is essentially what "debugging" means).

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

2. Basic debugging techniques for any PHP code 2.1. Ensure PHP is really runningStart out with "Hello world!." Here it is:

<?php echo "Hello world!"; ?>

Upload it to your server and see it in your browser before you proceed. You won't be doing any debugging until you have basic connectivity established. Maybe you named your index file index.php.html ... There's no point in writing 200 lines of code to discover this. This one line will let you know you have a problem and you don't need the other 199 lines of code. 2.2. "View Source" is not just your friend, but your BEST friendYou read this everywhere over and over again, and yet it can't be emphasized enough - PHP is not processed by your browser! Instead PHP generates content that your browser then processes. Whenever you see PHP produce something unexpected, the first thing you should do is to right click on the browser screen, and click "View Source" (or the equivalent in your browser; something with "Source" or "Code" in it). Your browser will open up a new window, and what you see there is the real PHP output. Whenever we talk about "output" further on, that output is the only thing we're interested in. 2.3. Find the branchDoes your PHP code have branching (if, switch, while, for...)? Put in debug statements. When your server is 3 timezones away you have no idea if any particular code executed. A simple

echo "Hi!";

will tell you execution got to a particular statement or line. If you see "Hi!" in the output, then PHP got there, otherwise not. This is just an extension of the "Hello world!" concept. Simply add something akin to the above within the branch you want to make sure was executed. 2.4. Dump variablesRegardless of whether you're dealing with a string, a number, or even an array, you can use

var_dump($var);

where $var is the name of a variable you want to output (notice there's no "echo" here). This will tell you the value of that variable, as well as its type. For strings, var_dump() would also tell you their length, and for arrays, it will also tell you the type and value of each array key and value. If you want to avoid disrupting the browser rendering, you can place the var_dump() output within an HTML comment, like:

echo '<!--';var_dump($var);echo '-->';

Don't want to put it in your HTML or comments? Or is there a problem with doing that? You can write to a file instead. Just choose a name for a file (whatever you want... let's say "debug.txt" for example), and make your PHP code write the values you're interested in it, like:

file_put_contents('debug.txt', print_r($var, true));

You'll notice the print_r() function. Similarly to var_dump(), that outputs information about a variable, although it tells you less things about arrays and strings (no types, no lengths). 2.5. Decode the error messagesMost of the time, the problem stares you in the face, in the form of an error message. The messages often sound cryptic, but if you look closely at the details they provide you with, you can often find and fix the problem. In particular, look at the file and line provided. See what's there. See what's required for that line to execute properly. Try to create a new file (just to test this one behaviour) with just this line and its requirements (a.k.a. "input"), and see if you get the same error. - If you do get the same error, ask yourself what's wrong with the input. Is there any other way you can express that input (e.g. if it's a URL, can you use an absolute instead of a relative one; if it's a number, must you be in a certain range, etc.)? What is expected to happen with that input? If this is not your own function, look at the relevant documentation for clues. - If you don't get an error, ask yourself what is different, and look for clues in the text of the message itself. Slowly, keep copying more of the "real" code into the test file, until you can reproduce the original error. If after hitting that point you can't figure out what's wrong, you're in a good position to create a topic in the forum, with the test code provided in it, along with details on the turning point.

  • Like 1
Link to comment
Share on other sites

3. Basic debugging techniques for some PHP codes 3.1. Problems with (MySQL) queriesUsing any SQL queries with MySQL? Write your query into a variable, and output the variable (as discussed above). There will probably be variables within the query, in which case they'll be rendered into their exact values when your code executes. Cut 'n paste the output from your "View Source" to a query line in phpMyAdmin, "MySQL Workbench" or another tool that allows you to execute queries. There you can see why MySQL is complaining about your query. (Note: The same applies to other database engines as well.) 3.2. Problems with cookies, session, redirects, caching, and moreIn addition to the stuff you see in "View Source", your browser sends HTTP headers, which your browser processes in order to determine how to deal with your content. These headers include rendering instructions (is it an image, an HTML document? Text you say... what charset?), caching instructions, redirect instructions, as well as cookies (with the session cookie being one such cookie) and more. The first step in diagnosing header related problems is seeing headers, which is not something you normally do. Depending on your browser, there are different ways of doing that.

  • Opera: Press Ctrl + Shift + I, and click on the "Network" tab. Any new HTTP requests your browser makes will be made available there, with the request and response headers being visible by clicking once on the HTTP request you're interested in.
  • Safari: Press Ctrl + Alt + i, and click on the "Network" tab. Any new HTTP requests your browser makes will be made available there, with the request and response headers being visible by clicking once on the HTTP request you're interested in, and clicking on the "Headers" tab.
  • Chrome: Press F12, and click on the "Network" tab. Any new HTTP requests your browser makes will be made available there, with the request and response headers being visible by clicking once on the HTTP request you're interested in, and clicking on the "Headers" tab.
  • Firefox: Firefox has no "built in" way of letting you view headers, but there are a few good add-ons for that, the most popular of which is Firebug. Using Firebug to inspect headers is similar as with other browsers - Press F12, click the "Network" tab, and click "Enable" if prompted. Any new HTTP requests your browser makes will be made available within that tab, with the request and response headers being visible by clicking once on the HTTP request you're interested in.
  • IE9 and above: press the F12 key, click the "Network" tab, and click the "Start capturing" button. Any new HTTP requests your browser makes will be made available there, with the request and response headers being visible by double clicking on the HTTP request you're interested in.
  • IE6 and above: IE8 and below have no "built in" way of viewing headers, but there are a few good add-ons for that, the most popular of which is Fiddler. This add-on can in fact also be used to inspect HTTP traffic from IE9 and Firefox as well. To use it, open up Fiddler, start browsing to the page, and you'll see the HTTP requests on the left. Click the one you're interested in, and you'll see details about it on the right. If you want your mind blown, check out the "Raw" tab.

3.3. Problems with mail()The mail() function does NOT in it of itself send an email, which is often the cause of many headaches when getting it to work properly on your own server. Just keep that in mind: The mail() function does not send emails. Instead, it asks a separate program (an SMTP server) to send an email.For UNIX (e.g. Linux or MAC), PHP has native support for "sendmail". Just like any other SMTP server or any OS, "sendmail" usually needs to be downloaded and installed separately. After you do that, you may have to open your php.ini, and set the sendmail_path directive to the path where sendmail is installed, and add the arguments too.For Windows, any SMTP server will do the trick, though you'll be contacting it over TCP/IP (you know, like with MySQL). You can specify the IP or domain name the program is running on with the SMTP directive, and the port this program is running on with the smtp_port directive. The default values for these are set to "localhost" and "25", respectively, so if you just install an SMTP server on your server, there's nothing else to configure.Some examples of SMTP servers for Windows include hMailServer, Pegasus Mail, Microsoft Exchange Server, the built in SMTP server (on Windows Server), and a bunch of others.In general, using the mail() function directly is a bad idea for a number of reasons, the most important being that everything is very "raw", which in turn opens the door for a number of security issues. Consider using a wrapper library like Zend_Mail, Swift Mailer or PEAR_Mail. In addition to preventing such security issues, they also make it easy to supply additional data to the SMTP server, such as credentials, SSL encryption and more.If you have other mail related problems (e.g. messages go to recipients' SPAM folder), chances are that something else needs to be configured at the SMTP server and/or you need to supply "correct" data to your SMTP server. For example, if you want to send an email from a GMail address to someone else, you'll have to do that through GMail's SMTP server, not your own SMTP server, and login to the SMTP server with the credentials for the email the message is from.To find out exactly what's wrong, enable logging at your SMTP server, and check the logs to see the full "conversation" between it and PHP. In addition, if your mail client allows it (GMail's site allows it), check out the received message in its "raw" form, to check out the mail headers the message ended up with. Those headers are similar to HTTP headers, and in addition to telling how the message is to be handled, they also contain data like a list of SMTP servers that were in contact with the message (starting at your SMTP server, and ending at the SMTP server of the recipient's provider). Any of those servers may add/alter/remove additional headers that you may have to deal with somehow (e.g. by adding/altering/removing some headers at your own SMTP server).

Link to comment
Share on other sites

4. "Advanced" debugging techniques for any PHP code (In reality, these things aren't "advanced" as in "difficult to grasp", but they do require some extra setup, hence they're not really "basic" either) 4.1. Use an editor with "syntax highlighting" for PHPJust because PHP can be written with just Notepad doesn't mean that you have to use it. In fact, it's a bad idea to do so, unless of course you have no other choice. There are countless other editors, and if you just search "PHP editor", you'll get a large list of editors, all of which have a feature known as "syntax highlighting". What this means is that the editor will color different parts of your code differently, based on what PHP is expected to interpret that part as. It might sound like just a silly cosmetic, but that's in fact the quickest way of finding syntax/parse errors in your code. For example, if you know that your editor colors strings as one color and loops with another, yet see a loop with the color of a string, you already know that you have a string above the loop that you haven't closed. Vice versa? You probably forgot to close another string above the mis-colored string. No colors? Chances are you're not within a "<?php" block. Unconvinced? This forum has a syntax highlighting feature built in if you use the "code" BBCode tag. It tries to guess the language, and color accordingly. An explicit "<?php" is enough to make it turn on PHP. Next time you have a syntax/parse error, "Preview" your post, where the code is surrounded in a "code" BBCode tag, and see if you can spot your error. While we're on the subject of editors... 4.2. Prefer editors with "code completion" for PHP What "code completion" (sometimes called "auto complete", "Intellisense" or other kinds of marketing nonsense) means is the ability of an editor to suggest possible things you may be trying to type. In addition to saving you time in typing new code, this ability is also useful for debugging - if you can't see a variable/function/class/whatever in the list of suggestions, chances are that you've mistyped it and/or that the editor is smart enough to know that you can't use that thing at that point. There aren't many editors with "code completion" for PHP, due to the fact that PHP is loosely typed and interpreted, which means that more often than not, anything could potentially be everything everywhere (simply put, things become known when you run the file, not while you're typing it), which means that editors need to be a lot smarter, and allow themselves the potential of giving you wrong information (and we don't want that, do we?). If you keep your code organized and in small isolated compositions (functions, classes, methods, etc.), use type hinting everywhere it makes sense, and use "DocBlocks" to document all of your code, you probably won't encounter misleading editor hints. Some editors with "code completion" for PHP include Adobe Dreamwaver CS6 (earlier versions only support it for built-in PHP functions and nothing more, while this version also includes support for PHP classes and your own functions/classes), NetBeans (7.2 also supports traits), PhpStorm, Eclipse PDT and Aptana Studio. 4.3. Install XDebugXDebug is the de facto standard PHP debugger, and for several good reasons too. The more you get used to it, the more its absence on other people's machines will frustrate you ;) . The most "basic" thing that XDebug is worth getting for is that it makes the output for var_dump() colorful (using HTML with CSS styles...), which may sound like just a cosmetic fluff, but if you're var_dump()-ing large arrays or objects, you'll find the output is significantly easier to read. Another, more important feature, is function stack traces. What this means is that if an error occurs, you can see the exact sequence of functions that was called to produce the error, starting with one in the file that execution started at. Combined with a var_dump() of the input data (starting with the last called function, and going back one by one to the first), you can quickly find the point at which your code started to behave weirdly (and thus resulting in the error further on). There are other "fancy" features in it too, such as code coverage, line-by-line debugging and profiling, but for best experience, you need additional tools (e.g. NetBeans , PhpStorm, Eclipse PDT and Aptana Studio support line-by-line debugging after you configure them for it; KCachegrind and Webgrind can view profiling information, etc.).

  • Like 2
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...