When APC appears to fail Drupal

There are quite a large number of resources on the internet that exist due to the error that springs up on Drupal sites with APC enabled:

Cannot redeclare class insertquery_mysql in /path/to/drupal/includes/database/database.inc on line 1774.

Whilst many of them provide work arounds like hacking core to include a class_exists() conditional, simply clearing the cache, disabling APC, upgrading to a (now non-existant) version of APC or just state that since it's not Drupal it's 'not our problem'; none really look to addressing the root cause of the issue.

This summoned a memory of my high school history tuition where I studied, and greatly enjoyed, the topic of Medicine through the ages. A saying that was first used by the Greeks and Romans in the time of Asclepius was that 'Prevention is better than cure'. Admittedly, they probably didn't use that phrase but the sentiment was definitely understood that a healthy, hygienic lifestyle would suppress and reduce the occurrence of illness. In the same way, it is a preferred method to find the root cause of a bug rather than attempt to work around the issue and increase obscurity.

By downloading and running a code sniffer over some of your custom modules, it's likely you'll turn up some interesting results.

Installing PHPCS

Most operating systems/distros will have their own way of code sniffing PHP for syntax, errors, coding standards and the like. A combination of either pear install PHP_CodeSniffer or brew install php-code-sniffer should be sufficient.

This will download the PHPCS package and allow you to use the code sniffer to tell you how bad your code and make you feel bad.

Tracing the bug

Whilst this isn't a certain surefire fix to the redeclared class issue, fixing this has on occasion made that go away. Since PHP 5.3, passing a variable by reference has been deprecated with PHP 5.4 removing it entirely. Passing by reference is now implicit so no additional declarations are required except for on the function declaration.

We can detect where these call time pass by reference issues arise with the following line for our code sniffer.

phpcs --extensions=php,module,inc,install --standard=Generic --sniffs=Generic.Functions.CallTimePassByReference /path/to/modules

This takes any files with the php, module, inc or install extension and runs the sniff for call time pass by reference notices/errors. This will output something similar to the following for an error that needs fixing:

FILE: ...path/to/my_deprecated_code.module
--------------------------------------------------------------------------------
FOUND 1 ERROR(S) AFFECTING 1 LINE(S)
--------------------------------------------------------------------------------
 36 | ERROR | Call-time pass-by-reference calls are prohibited
--------------------------------------------------------------------------------

From here it's trivial to alter the function call so my_function(&$var); becomes my_function($var); and with the errors disappearing, so too, hopefully, will the redeclaration errors!

 

Comments

Submitted by Donovan Mueller (not verified) on

Thank you so much for posting this! I think you just saved me hours, and hours. The `class_exists()` solutions were not working for me. Clearing the APC opcode cache wasn't working. But it looks like getting rid of a typo in the form of a pass-by-reference solved the problem.

THANK YOU SO MUCH!

Submitted by Donovan Mueller (not verified) on

Actually, this did seem to resolve it. I just had to restart MySQL and Apache on all the servers. Thank you!

Restarting Apache would have had the site-effect of clearing APC (I'm assuming you have that as opcode cache). Code can sometimes get held up in APC so the combination of fixing the original code as well as clearing opcode cache gives you a working site!

Add new comment