Fatal Error Cannot Redeclare Function I

Fixing the PHP error: Fatal Error Cannot Redeclare Function


Sooner or later, you're likely to see an error like this one:

Fatal error: Cannot redeclare functionname() (previously declared in path/somefile.php:49) in path/somefile.php on line 55

In this article, we'll look at what causes that message and how to fix it.


The Problem

When you put a function like the one below in your PHP code, you are 'declaring' it. Essentially, you are telling PHP to hang on to the function in case someone calls it. The code of the function is not executed, but rather saved for later use. If the function is never called, its code is never executed.

function add ($a, $b) {
    return $a + $b;
}

The function above simply adds two numbers. If we add this code below the function declaration, it will display the result of the addition:

echo add (2, 3);
/* Displays the number 5 */

So far, so good. But what if we do this?

function add ($a, $b) {
    return $a + $b;
}

function add ($a, $b) {
    return $a + $b;
}

When PHP sees the second declaration, it throws a fit because there is already a function with that name in memory. This makes sense because the two functions might be quite different. For example, one might be for adding two numbers and the other might be for adding a record to the database. Using one when the other is intended could have disastrous results. PHP is very cautious about this. It will throw the error even if the functions are identical. In fact it will throw the error even if they are both empty, like this:

function add () {
}

function add () {
}

The error message tells you the name of the function, the two files where it is used, and the respective line numbers involved. Note that the first line number in the error message will be the line with the first declaration of the function (line 1 above). Oddly, the second line number indicates the *end* of the redeclared function (line 5 above).


How it Happens

The examples above show one way to trigger this error, but that cause is extremely unlikely. Developers will almost never insert the same function twice in their code, and if they did, their testing would reveal it right away and they'd fix it before the code was ever released.

One common cause of the error is for the file with the code in it to be included twice. It's easy to trigger this error by using the same code twice on the same page. You might, for example, have a simple snippet that returns the current year and shows the year more than once on a page. In this case, the two files identified in the error message will be the same.

Another, less common, cause is that two different code snippets on the same page (or a snippet and a plugin, or two plugins) have different functions with the same name. Most developers know enough to give their functions unique names so they won't collide with other people's code. For example, our add() function could be named addIntegers() to help prevent collisions.


Solutions

If the error message you see lists the same file twice, there's a simple solution: wrap the function in if (! function_exists('functionName') {}. The developer should have done this if there's any chance that the code will be used more than once on the same page. For our add() function, that would look like this:

if (! function_exists('add')) {
    function add ($a, $b) {
        return $a + $b;
    }
}

Now, if the function already exists, PHP will ignore the declaration and no error will be thrown. The exclamation point in the first line above means NOT, so the code inside the curly brackets will only be processed if the function doesn't already exist. If the author of the function has forgotten to do this, you can fix the problem by adding the first and last lines of the code above just above and below the problem function, changing the name of the function in the first line to match that of the problem function.

If at all possible, let the developer know about the issue so they can fix the problem and release a new version.


Coming Up

The solution above won't solve the problem of another bit of code on the page using its own add() function, however. In that case, the two files in the error message will be different. One solution would be to change the name of one of the functions. This can be tricky, because you also have to change the name in every place the function is called. A much better solution is for the developer to put the function inside a class. We'll see how to do that in the next article.



Comments (3)

  1. MellFotoStudioFeb 08, 2016 at 07:19 AM

    Wrapping a function inside its if-not-exists won't work on other redeclarations, as you have noticed, but it most notably will not work when there are two different functions that share a name. In fact, in that particular case - wrapping your own function in an if() will make matters worse, because not only will you be getting the wrong function to do your work, you'll be obscuring this fact by preventing PHP from throwing a redeclaration error. This will be esp. hard to debug if you happen to reuse some code and modify it just a little.

    One way out of this mess is to assume a particular naming scheme, like for example bgw__* (where bgw would stand for "Bob's Guides Webpage", or something). That should avoid most collisions, and the more verbose you are, the better a chance it would have. That's a lot of verbiage to type in, though, and can be forgotten.

    The other method, introduced by PHP7 IIRC, is by using namespaces - it's essentially the same idea as I described above, but it's built-in functionality that allows you to 'fire and forget'.

    I think it would be wise to point out that using such if() conditions is only wise for debug purposes, and that only if you have good organisational skills. The only two legitimate issues this prevents is a) when you have a function definition that you may end up including again through some heavily convoluted and opaque code (and which can much more easily be fixed by using include_once or require_once and refactoring to move function declarations/definitions to a common place), and b) whenever you're working with one or possibly two more devs that tend to produce very similar-sounding function names (in which case it's still better to just agree on common collision avoidance methods).

    To sum up: wrapping redeclarations in if() statements makes the code harder to debug and doesn't actually solve the underlying problems. Receiving an error about a function already existing should always alert you to a bigger issue with your code. What does help is either a) using namespaces, or if these are unavailable to you or simply too much of a pain - b) putting these functions into abstract tool classes - something I understand you were about to tackle next?



    And what to do when you need to include a specific script more than once? Separate the function declaration into a separate script and include it in all instances via include_once or require_once - that works on file level, so if you then get a name collision error, you will know that there's something seriously wrong going on.





    As for why PHP only notices the issue at the ending curly bracket, that's because your code is only parsed after it's been lexed, or tokenized. The tokenizer is the part that converts your PHP code into symbols (like "words") which are then analyzed by the parser (as logical "sentences"). The parser only works on complete chunks of code (again, "sentences"), and so it becomes obvious that the parser only notices the redeclaration error when it receives the entirety of the redeclaration. (This is also the reason why a missing semicolon will be noticed not at the spot where it's missing, but where the existence of the next piece of code makes it obvious that something is missing by now.) Execution is halted at the point where the error was detected (which is computable - ie. "right now"), not necessarily where it actually happened (which may not be computable per se).

    Also, not sure how much C actually scales into standard PHP nomenclature, but as far as PHP-OOP is concerned you can declare a function w/o actually defining it (ie. explaining in code what it's supposed to actually do; a definition is also a declaration by necessity, but not the other way around). What you did above was technically a definition. But that's just me being a smarty-pants, pls forgib. ;)

  2. MellFotoStudioFeb 08, 2016 at 07:36 AM

    As a side-note -- a thought to consider for why PHP raises an error for a function definition that is identical in every respect: functions/scopes may have static variables. These variables are remembered between function calls, so even though a function's definition may be identical, its resultant state will not be. Consider the following code:

    function test(){
       static $ranTimes = 0;
       $ranTimes++;
    } // ranTimes is now 0

    test(); // ranTimes is now 1
    test(); // ranTimes is now 2

    function test(){
       static $ranTimes = 0;
       $ranTimes++;
    } // what should ranTimes be now? 2 or 0?


    If the second definition (ie. a redefinition) were to be accepted due to being identical, it would nevertheless reset the static counter back to 0 (possibly?! WHO KNOWS?!), and besides ambiguity - it would obviously not be what we want.

    There are other worms in this little can, so the obvious and logical thing to do is to flat-out not accept redefinitions.

    Note: there are other mechanisms in PHP that allow many cool things to happen: lambda functions (defining no-name functions by their procedure on-the-fly), namespaces, eval (which is apparently universally considered to be evil), classes and even a certain level of overloading. Of particular note is pointer-like abstraction which allows you to select variables and functions by variables, like so:

    $myFunction = "strrev";
    $myVariable = "someVariable";

    $someVariable = "Alpha";

    $$myVariable = $myFunction($$myVariable); // this is equivalent to "$someVariable = strrev($someVariable);"

  3. Bob RayApr 02, 2016 at 03:20 PM

    Excellent points, but the article (and I should have made this clearer) is aimed mainly at users running into this problem because of someone else's bad coding. They don't want to mess with that other coder's logic, and don't know where the problem is. They just want to make the error go away -- and the error message tells them exactly where the troublesome class declaration is.

    As you say, the proper solution is namespaces, but again that's a solution for the coder, not the end user of the code.


Please login to comment.

  (Login)