Most of us who work with Drupal on a regular basis have probably come across this error at some point:
Warning: Invalid argument supplied for foreach() in element_children() (line 6xxx of .../includes/common.inc).
The error is relatively self explanatory. Something that isn’t iterable was passed into a foreach loop. The tricky part about debugging this one is that a lot of modules call element_children()
and it can be hard to pinpoint where the error is coming from. Sometimes by process of elimination, you can figure it out, but the other day I was getting it intermittently and I needed some help. Here’s a little snippet I inserted at the top of element_children()
:
if (!is_array($elements)) { // Print a function backtrace (needs devel module). ddebug_backtrace(); // Supress the error return array(); }
It’s pretty simple. We just check if $elements
is an array (which it should be if it’s being passed into element_children()) and print a function backtrace if it’s not (ddebug_backtrace()
is provided by the devel module). This should point you in the direction of the culprit. In my case it was a custom hook form alter that was acting on an array key that sometimes wasn’t there. Total time to fix: about 2 minutes. Here’s what element_children() looks like with the little debug snippet (don’t forget to undo the snippet when you’re done)
/** * Identifies the children of an element array, optionally sorted by weight. * * The children of a element array are those key/value pairs whose key does * not start with a '#'. See drupal_render() for details. * * @param $elements * The element array whose children are to be identified. * @param $sort * Boolean to indicate whether the children should be sorted by weight. * * @return * The array keys of the element's children. */ function element_children(&$elements, $sort = FALSE) { // BEGIN: debug code if (!is_array($elements)) { // Print a function backtrace (needs devel module). ddebug_backtrace(); // Supress the error return array(); } // END: debug code // Do not attempt to sort elements which have already been sorted. $sort = isset($elements['#sorted']) ? !$elements['#sorted'] : $sort; // Filter out properties from the element, leaving only children. $children = array(); $sortable = FALSE; foreach ($elements as $key => $value) { if ($key === '' || $key[0] !== '#') { $children[$key] = $value; if (is_array($value) && isset($value['#weight'])) { $sortable = TRUE; } } } // Sort the children if necessary. if ($sort && $sortable) { uasort($children, 'element_sort'); // Put the sorted children back into $elements in the correct order, to // preserve sorting if the same element is passed through // element_children() twice. foreach ($children as $key => $child) { unset($elements[$key]); $elements[$key] = $child; } $elements['#sorted'] = TRUE; } return array_keys($children); }
Photo Credit: Web Scrapbook