Joomla! 1.0.12 Cannot redeclare error in admin section

This article is incomplete and was first written in June 2007
for the BeezNest technical website (http://glasnost.beeznest.org/articles/360).
This article is meant to help people who run into the same problem as I did, and hopefully will help me next time I have to deal with the same problem as well.

The problem appearance

Now OK, this was a peculiar situation, but I had to move a Joomla! 1.0.12 installation (which had just been migrated from Mambo to Joomla! if I remember well) from one server to another. Work had already started on this and after a lot of time finding my way through (various URLs changes etc) I finally managed to install the site on the new server. The public site seemed to work (except the login feature) but the administrator section was impossible to use. For each of the components, only the header and an error message of this type appeared:
Fatal error: Cannot redeclare showcategories() (previously declared in /home/w/workplace/public_html/administrator/components/com_categories/admin.categories.php:113) in /home/w/workplace/public_html/administrator/components/com_categories/admin.categories.php on line 251
This made it completely useless to have an administration section.

The problem logic

Now I don't know *why* exactly, but this problem appeared only after the move and seemed to stick deep enough to prevent any quick solution. The problem was that for some mysterious reason every component was loaded twice. Not knowing very well my way into Joomla!, the first thing I did was look at the component-loading process, but this didn't seem to be the problem (using an include_once() rather than an include() in there lead to the tool not displaying at all). This call is in includes/frontend.php, in mosLoadComponent(). It seems also that this problem might be caused by the integration of AJAX or dynamic javascript functions which *might* trigger the double-load of a script, although this shouldn't be a problem as they will be loaded twice but not in the same request. Anyway, digging deeper, I couldn't find an easy solution but I found that all the components scripts were more or less having the same problem:
  • the first function declared in the script was redeclared, causing the problem
  • every main script executes code before declaring functions
  • every main script has the code *and* the functions declarations in the same script, making it impossible to reload without redeclaring the functions

The solution

Now let's dice one of these problematic scripts in pieces. The problematic scripts, for me, are *all* in administrator/components/com_something and are *all* the admin.something.php ones. Each one of these looks like this:
  //1. Ceck the script isn't loaded directly
  //2. Execute code (generally contains includes and a switch statement)
  //3. Declare functions+classes
Now the first logical thing to do would be to surround the functions+classes declarations by a condition like
  if(!function_exists('showSomething')){
   //functions declaration
  }
where showSomething is the name of the first function declared and functions declaration contains the whole series of functions declarations up to the end of the script. We let ourselves only check for the first function because the script is always loaded in one piece, so if the first one doesn't exist, the others don't either, and inversely. Now if we only try this change, we still have a problem, which is that now the script is trying to access functions that haven't been declared at all. Why is that? That's because when we added the conditional check above, we introduced a side-effect that causes the functions declarations not to be visible when the first bit of code (the switch statement for example) is executed. When a function definition is inside a conditional check, the code (including the functions declarations) is executed in it's sequential order, rather than having the code executing and already be aware that there are functions declarations in the script. I guess the PHP interpreter sees functions and classes declarations are priorities when parsing a script, but that it can't do that if they are inside a statement (because the statement has the same priority as the others like the switch, and comes afterwards). Anyway, the easy way to fix this is to reorganise the script into this structure:
  //1. Ceck the script isn't loaded directly
  if(!function_exists('showSomething')){
   //3. Functions+classes declaration
  }
  //2. Execute code (generally contains includes and a switch statement)
That solves the problem. However, the solution is only for one component, and you will have to apply the change to all your components one by one… yes, boring… If you have the same problem and want somebody else to take care of it, you can contact me for a quote by sending an e-mail to ywarnier [at] beeznest [dot] net