Red Herring Error : Class name must be valid object or string After just having spent two days trying to get to the bottom of a particularly weird bug I thought I'd post up what my question would have been &mdash; if I had taken the time to write it &mdash; and then post my answer also, just in the hope of helping other people avoid the headache.


  PHP Fatal error: Class name must be a valid object or a string in /includes/common.inc on line 7522


This was the starting point. I got this error &mdash; along with a typically pleasant WSOD &mdash; after creating a new install of my site on a localhost. The strange thing about it was that I had almost exactly the same setup working on another machine. The code was served by GitHub and so was identical, the database was a direct dump from the original site, php was configured as expected and versions were only a 0.0.5 out (5.3.15 and 5.3.10), both Drupals were version 7.9 ... everything should be working.

What made this weirder still was the fact the site would work directly after a drush rr, however, it would break immediately after a drush cc all, or on refresh.

This led my collegue and I traipsing in circles, debugging common.inc and modules.inc trying to find a clue as to what was going on. What we discovered was that after the reset registry the correct entity_info array was built, but after the clear cache, we only got part of the full entity_info array.

Investigating further we found rather ridiculously that the following code &mdash; taken from module.inc &mdash; could not find particular functions in particular module files that we knew to exist.

foreach ($list as $module) {
  $include_file = isset($hook_info[$hook]['group']) &amp;&amp; 
    module_load_include(
      'inc', $module, $module . '.' . $hook_info[$hook]['group']
    );
  // Since module_hook() may needlessly try to load the include file again,
  // function_exists() is used directly here.
  if (function_exists($module . '_' . $hook)) {
    $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
  }
}


This could only mean that at the point this code was being executed certain files that should have been included by now, weren't. What made this even more baffling was that if we called the following outside of any of the caching code, it returned the correct entity_info array.

$entity_info = module_invoke_all('entity_info');


This meant that there wasn't anything wrong with the files, it just seemed to be the caching system. To cut a rather long story short, because we didn't have anything modifying the core drupal caching system, we decided to resort to the good old trial and error disable all modules and enable one by one. Great.

This took some time but we managed to whittle everything down to one bespoke module, which we then trial and errored function by function call. Until we got the culprit:

/**
 * Helper function to redirect an actual submit to the ajax handler
 */
function microsites__admin_settings_submit(&amp;$form, &amp;$form_state) {
  return microsites__admin_settings__ajax_button(&amp;$form, &amp;$form_state);
}


So I guess my question &mdash; apart from being, what can cause PHP Fatal error: Class name must be a valid object or a string error &mdash; would be what out of the above function could cause such a disastrous error, and in such a weird manner?
For those who have been using PHP a while, it should be obvious what is causing the issue, although what wont be obvious is why Drupal didn't make a song and dance about it.

Basically the cause of the WSOD were the two ampersands denoting call time pass by reference. Something that has been deprecated in PHP for a while. The reason why they were there at all was just a copy and paste typo.

return microsites__admin_settings__ajax_button(&amp;$form, &amp;$form_state);


The above should have been:

return microsites__admin_settings__ajax_button($form, $form_state);


With the above change made, everything magically started working again.

Now I might get some people assuming that we just hadn't been keeping track of our errors, but we had as much logging enabled as possible... at no point did either PHP or Drupal complain about the call time pass by reference. Instead what Drupal seemed to do &mdash; and only after clearing cache I might add &mdash; was fail to include other files once it had hit this illegal / deprecated syntax, which then went on to create malformed entity_info arrays.

I have since tested this on other files, and all it takes is to add a call time pass by reference and it breaks Drupal, at least for all my localhost setups anyway... that is, unless the following has been specified in the php.ini:

allow_call_time_pass_reference = On


If anyone can ascertain as to why the silence (considering all other PHP errors and warnings are shown), why it broke other files loading, and why the problem only affected when running after a cleared cache, I'd be interested to hear. 

Maybe upgrading to 7.22 would fix a few of the above... but in future I'll make sure I double check coherence between my entire php.ini(s) I think; rather than spend a few days trying to bash through a brick wall using only a toothpick.

update

Just to answer Clive's question, this was the output in the apache error log after I've just tested the same problem again:

[Thu Apr 11 11:15:29 2013] [notice] Digest: generating secret for digest authentication ...
[Thu Apr 11 11:15:29 2013] [notice] Digest: done
[Thu Apr 11 11:15:29 2013] [notice] Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8r DAV/2 PHP/5.3.6 configured -- resuming normal operations