So you're coding along, developing your site, minding your own business, when you load a page you see some totally vague, obscure error message such as:
warning: Invalid argument supplied for foreach() in /modules/node/node.module on line 504.
Where do you even start debugging something like that?
Well, you could start with looking at line 504 of node.module...
foreach ($param as $key => $value) {
Uh, yeah. That's helpful.
If you were astute, you might also observe that line 504 is inside of the node_load() function. So that narrows it down to... only one of the 80,000 places node_load() might be called from one of your core or contributed modules or themes. Ugh...
You could decide to get all fancy, and install an IDE like Komodo, Eclipse, or Zend, and use their real-time debugging features to step through the code one line at a time to figure out what's happening. It's pretty time-consuming, and it takes up lots of resources on your machine, but it'll probably help you nail it down if you are observing carefully.
Or! You can debug the quick and dirty way! Read on to find out how! In bootstrap.inc, find the function definition for drupal_set_message and place the following code at the top:
function drupal_set_message($message = NULL, $type = 'status') {
// DEBUG: Go track down that stinkin' error...
if ($type == 'error') {
$message .= '
'. print_r(debug_backtrace(), 1) .'
'; } // END DEBUG if ($message) { ...
What will this do? It'll make that error above become something like this instead:
warning: Invalid argument supplied for foreach() in /modules/node/node.module on line 504.
Array
(
[0] => Array
(
[file] => /includes/common.inc
[line] => 552
[function] => drupal_set_message
[args] => Array
(
[0] => warning: Invalid argument supplied for foreach() in /modules/node/node.module on line 504.
[1] => error
)
)
[1] => Array
(
[file] => /modules/node/node.module
[line] => 504
[function] => error_handler
[args] => Array
(
[0] => 2
[1] => Invalid argument supplied for foreach()
[2] => /modules/node/node.module
[3] => 504
[4] => Array
(
[param] =>
[revision] =>
[reset] =>
...
)
)
)
[2] => Array
(
[file] => /sites/all/modules/custom/custom_module/custom_module.module
[line] => 10
[function] => node_load
[args] => Array
(
[0] =>
)
)
[3] => Array
(
[file] => /includes/form.inc
[line] => 365
[function] => custom_module_form_alter
[args] => Array
(
...
Note: If you have many errors on a page, this will probably crash your browser. ;) That's why we call it "Quick and Dirty." ;)
Uh. So what the heck is all of that crap? It's called a backtrace... it's showing you in reverse order the functions that were called, and the arguments that were passed into each, in order to get to the current spot in the code.
Let's take just chunk #0 and dissect it:
[0] => Array
(
[file] => /includes/common.inc
[line] => 552
[function] => drupal_set_message
[args] => Array
(
[0] => warning: Invalid argument supplied for foreach() in /modules/node/node.module on line 504.
[1] => error
)
)
?>
This tells me that in /includes/common.inc on line 552, the function drupal_set_message was called, and was passed in two arguments. If I check the API documentation for drupal_set_message, I can see that the first argument is the message to display, and the second is the type of message.
If I follow down the list, #1 tells me that drupal_set_message was called by error_handler because of something that happened on line 504 in node.module. (Duh, I knew that one already.)
#2 says that this was triggered by a call to node_load from custom_module.module on line 10. Great! Now I know that custom_module.module has something to do with the problem. That helps narrow the problem down significantly.
But, as an added bonus, I also know that node_load was passed an empty value into it as an argument, where normally this would be a node ID like 56. That's not going to go over well... unless I tell it what to load, how is Drupal not going to puke all over itself?
#3 helps me narrow it down even further.. I know now that this was caused by a call to the custom_module_hook_form_alter function.
I can keep reading; the backtrace will detail all of the function calls that happened, all the way as far as index.php. But I have enough information now to start hunting for the bug.
If I look at my hook_form_alter in custom_module.module, around line 10, I might see something like this:
if (arg(0) == 'node') {
$node = node_load(arg(1));
}
Note: I didn't actually write such code, but needed an easy example. ;) After a bit of head-slapping, I realize that I'm on the path ?q=node, so there is no arg(1), therefore it's passing a NULL value into node_load(). Further, my code blindly assumes that I'm on a path like node/34, but doesn't check to make sure I'm not on a path like node/add/blog. Eek. Let's try this again:
if (arg(0) == 'node' && is_numeric(arg(1)) {
$node = node_load(arg(1));
}
Voila! No more errors. For trickier bits, and doing something like debugging form.inc ;) you probably want to step up and make a real-time debugger part of your developer arsenal. But to help you nail down the cause of an error quickly and easily, this can be a useful tip.