Jump to content

Fatal error: Cannot redeclare function()


Domhnall

Recommended Posts

Hi all

 

I'm trying to move an old project from php4 (4.0.4pl1) to the latest php5 (5.2.8 ).

 

When I run with php5 I get a lot of "Fatal error: Cannot redeclare xxxx" errors. On inspection it looks like instead of using methods like include_once and require_once the original developers put in C style header guards like this:

 

if (!defined("TESTFUNCTION")) {
define("TESTFUNCTION", true);
} else {
return;
}

 

While this appears to work fine in php4, in php5 it seems like the interpreter parses the entire file again even though the return statement is hit.

 

Does anyone know the reason for this? Is it possible to get this to work in php5? Or am I just asking for trouble with such a massive jump in the php version!

 

Heres a couple of simple files that can replicate this happening:

 

testfunction.php

<?php
if (!defined("TESTFUNCTION")) {
define("TESTFUNCTION", true);
} else {
return;
}

function testFunction() {
echo "This is a function";
}
?>

 

includetest.php

<?php
include('testfunction.php');
include('testfunction.php');

testFunction();
?>

 

Result:

Fatal error: Cannot redeclare testfunction() (previously declared in /opt/opwv/sw/msp/6.6.2/mscc/cac/prod/docroot/cac/testfunction.php:9) in /opt/opwv/sw/msp/6.6.2/mscc/cac/prod/docroot/cac/testfunction.php on line 10

 

Cheers

Domhnall

Link to comment
Share on other sites

Your including the file twice, of course you will get that error. If you are going to include a file twice (which I have no clue why you would) then you would need to do this:

 

<?php
if (!function_exists("testFunction")) {
  function testFunction() {
     echo "This is a function";
  }
}
?>

 

And that should stop the error. Oh and also, the return; value in the include, I do not think that works. So I would just remove that part altogether. But yea, you really should only include it once, there is no reason to have it included multiple times.

Link to comment
Share on other sites

Given that you can indeed use the return statement to return control back to the file that did the including, i would imagine this arises out of PHP's look-ahead ability.

 

Unlike some languages, you need not declare a function prior to it's usage in your script - it can appear anywhere. So, whilst in other languages, the function definition would never be arrived at the second time that file is included, PHP has already "seen" the function before even considering the rest of the logic flow.

Link to comment
Share on other sites

Thanks for the replies. Sorry perhaps my example wasn't very good.

 

In the example I included the file twice just to show what was happening. In the real code the problem is caused were a lot of the time files are included twice via some other included file so you end up with a loop in the include "tree".

 

For example (imagine like this but even more horrible!):

fileA.php includes incA.php

fileA.php includes someutil.php

incA.php includes someutil.php

 

I understand that including twice would cause the function to be defined twice and result in the error but is interesting is why the header guard method seemed to prevent this in php4 but not in php5 and if it is somehow possible to replicate the php4 behavior in php5.

 

GingerRobot, for what you say the other option I might have is to mass change all the include()s to include_once()s. I'm slightly worried about any side effects though.

Link to comment
Share on other sites

 

 

This is directly out of the php4 to php5 migration section in the php manual -

If there are functions defined in the included file, they can be used in the main file independent if they are before return() or after. If the file is included twice, PHP 5 issues fatal error because functions were already declared, while PHP 4 doesn't complain about it. It is recommended to use include_once() instead of checking if the file was already included and conditionally return inside the included file.

 

That code is attempting to use an include statement like it is a subroutine "call" statement and to conditionally define functions in that "subroutine" on the first "call". That is just poor programming, but I am guessing because the manual has a statement that exactly matches what the code is doing that the manual must have contained an example using that code at some point in time.

 

The solutions from more desirable to least desirable -

 

Organize your logic correctly so that functions are defined near the start of your main file (usually by placing the function definitions in their own file(s) and including them.)

 

Use include_once/require_once

 

Conditionally define functions as premiso has posted or in the existing code, if the function definition is placed inside of the if() logic, it will be conditionally defined only on the first include (untested but should work.)

Link to comment
Share on other sites

 

For the new information in your last post, if the included file also contains code that produces content at that point in the document, then you cannot just switch to the _once() version of include/require as that content will no longer be produced.

 

If the included files only contain function definitions, you can change the include/require to include_once/require_once.

 

If there is content being produced in the included files, I recommend moving the function definitions into the if() statement.

 

Short-answer: it is time to properly organize where and when functions are defined and files are included.

Link to comment
Share on other sites

Argh!

 

Thanks PFMaBiSmAd I read over the manual but totally missed that bullet point, sorry :( !

 

I'd love to reorganize everything but the project I'm moving is so huge and old that it would take awful long time. I guess I was hoping for a quick fix but if it has to be done it has to be done!

Link to comment
Share on other sites

 

Actually, I just tested my suggestion of putting the function definition inside of the if() statement and it does work AND because of the return; statement in the else condition, content being output later in the included file will only be output the first time. So it is likely that the included files only contain function definitions and since the original programmers did not better organize the code or use the _once version of include/require, you are left with this task now.

Link to comment
Share on other sites

An idea I just thought of.

 

How many includes do you have that just include a function?

 

Why not put all these functions into one include and just include that one file each time? If the include does nothing more than include a function, I would just combine those files and included a "main.functions.php" As long as it is not something insane like 50 includes, this should be just peachy.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.