I’ll start with two questions:
1. Have you ever used the devel module’s dpm() function?
2. Have you ever used a PHP debugger with Drupal?
If you answered “yes” to the first question and “no” to the second, this post is written for you (and if you didn’t, well, you can probably skip it). I have a hunch there are lots of you out there; I’d certainly have answered that way myself for far longer than I care to admit. Suffice it to say that my debugger is now a tool that you’d have to pry from my cold, lifeless fingers.
Still with me? Great. Without further ado:
First things first: getting your debugger set up.
This is the hardest part by far and, alas, I’m not going to offer much help. There’s plenty out there already on the subject, so fire up Google and find yourself a good tutorial. The basic steps are:
1. Pick an IDE (“Integrated development environment”) if you don’t already have one. I’ll be usingPhpStorm here, but you could just as easily use Komodo IDE or the open-source Eclipse. Note that simpler text editors — BBEdit, TextMate, Sublime Text, Notepad, or even Coda — unfortunately won’t cut the mustard here.
However you get there, the ultimate goal is to be able to do something like the following:
1. In your IDE, turn debug listening on. In PhpStorm, you do this by toggling the “Listen debugger connections” button.
2. Then, set a “breakpoint” by opening the index.php file from your Drupal site and clicking in the margin to add a little red dot.
3. Finally, in your browser, load the homepage of your local version of the site. This will, of course, start executing the php code that makes up Drupal, and if you’ve got everything set up right, it will pause as soon as it gets to your breakpoint. The PhpStorm window will jump in front of your browser, and you’ll see something like this:
If it doesn’t happen this way the first time, here’s some consolation: you’re not alone. Every time I’ve set up a debugger, it’s been a painful trial and error process, and I suspect that’s not unusual. Stay strong, keep at it, and come back for the rest of this article when you’ve got it working.
Put your debugger to good use!
Now for the good part! First off, let’s set a breakpoint somewhere a bit more useful than your index.php file. If your IDE is still paused at the first breakpoint, click on the breakpoint to remove it, then hit the ‘resume’ button to allow the page to continue loading. (If you don’t, you’ll notice the page in your browser stays stuck in a sort of limbo where it looks like it’s trying to load, but never gets there. Make a mental note of this; I can’t tell you how often I wonder why a page is taking eons to load, only to remember that I’ve left it stuck on a breakpoint.)
Next, open up page.tpl.php from the theme you’re using and set a new breakpoint on the first line with a PHP statement, then refresh the page in your browser. (A few more things to note: first, the breakpoint won’t work if you put it on a line that only has HTML; it is, afterall, a PHP debugger. Second, it also won’t work if the line it’s on isn’t getting executed— for example, if it’s inside an ‘if’ statement that evaluates to FALSE, or, heaven forbid, in a section of code that isn’t required for the current page, like the page.tpl.php file for an inactive theme.)
This brings us to the first of many advantages a debugger has over the dpm() function; the ability to see all available variables at once, not just the one you dpm’d. In the screenshot above, you’ll notice that the ‘Variables’ section shows not only the value of $logo, but also, for example, the value of $is_admin, $is_front, and so on. To get similar insight with dpm(), you’d not only have to use it dozens of times (dpm($is_admin); dpm($is_front); etc.), but you’d also have to know all those variables were even available in the first place!
While that’s sinking in, scroll a little further through the list of variables and you’ll find a few bonuses: $_COOKIE, $_SERVER, and $_SESSION, to name just a few. $GLOBALS will show you all the global variables that Drupal sets for you like $base_url, $user, and $conf. Needless to say, there’s a lot of information here, and any of it that you’re not familiar with is well worth exploring.
Stepping Though Code
Unimpressed by the variables? Fear not, because there’s plenty more. In addition to the more or less static view of what’s going on at your breakpoint, you can also “step through” your code. To see how this works, click the ‘Step Over’ button in your debugger to advance it to the next line. (In PhpStorm, the blue highlighting indicates your current position; when you click ‘Step Over’, it should move down a line.)
In the screenshot, you’ll see that my debugger is now inside the ‘if ($logo)’ conditional statement; evidently, the condition is true. In this case, that’s not surprising, since one glance at the variables section shows that the $logo variable is set. Of course, you could easily have a much more complex conditional; rather than pondering over whether it’s true or not, you can just click ‘Step Over’ to watch where the blue highlighting goes. If it skips right past, you’ll instantly know the condition wasn’t met and can then look closer to figure out why.
At this point, I could continue using the ‘Step Over’ button to work my way down the page line by line. Any variables that were modified would be updated in my variables pane (for example, when I moved past render($page[‘logo’]), $page[‘logo’][‘printed’] would be set to TRUE). If I wanted to skip ahead 50 lines without monotonously clicking ‘Step Over’ 50 times, I could just put my cursor half-way down the page and then click the ‘Run to Cursor’ button instead.
But let’s say that I want to know what’s going on inside the render() function. Rather than clicking ‘Step Over’, I can use the ‘Step Into’ button instead. When I click ‘Step Into’, PhpStorm will find the file that contains that function (in this case, common.inc), open it up, and show me exactly what’s going on with the variables inside render(). From there, I can step over each line of the render function, step deeper into other functions, or click ‘Step Out’ to go back to where I left off in page.tpl.php.
In case you’re not overwhelmed yet, I’ll throw one last debugging feature your way. Just to the left of the variables pane is something called the stack trace (labled ‘Frames’ in PhpStorm). This helpfully shows you the list of functions that were called, one inside the other, to get to your current spot. At the very bottom of this list, you’ll see index.php (since that’s where every request to Drupal starts). Just above it, you’ll see the funtion that was called from index.php (most likely menu_execute_active_handler()), and so on all the way up to where your breakpoint is. If you wanted to, you could click the ‘Step Out’ button to work your way down the list one function at a time. Alternatively, you can actually just click a function in the stack trace to jump to it without stepping through the code, which means you can see what’s going on without losing your spot.
Phew! That was a lot of text and screenshots, and we really just scraped the surface. Mastering the debugger is, like most things, probably best done by getting your hands dirty, but hopefully I’ve at least provided some motivation to get to that point. Of course, if you have questions (or debugging tips of your own), feel free to leave a comment below.