Fatal Error cannot redeclare function Part 1

Understanding the "Cannot redeclare function" error in PHP.

By Bob Ray  |  November 19, 2024  |  7 min read
Fatal Error cannot redeclare function Part 1

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 via an include or require statement. It's easy to trigger this error by accident. For example, you might have a file containing utility functions. One part of your program might include that file because it intends to use one of the functions in it. Later, another part of the program might include the same file again to use the same function, or more likely, another function in the same file.

Another, less common, cause is that two different code snippets on the same page (or a snippet and a plugin, or two plugins, or two separate included files) 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. To be even more cautious, you could add a unique prefix to the name of the function.

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.

Be careful with this method. When using if (! function_Exists()), PHP will ignore the declaration if the function already exists, but the function that already exists might not be yours. If someone else's add() function has been included earlier on the page, your code will try to use that function when it sees the function call. That's another good reason to use unique names for your functions.

If the problem is caused by a file that's included twice, another solution is possible. You can change include or require to include_once, or require_once. Once you do that, if the file is requested for inclusion a second time, PHP will realize that it's already been requested and will ignore the request.

There is also a danger with this approach. It rarely occurs, but I have been bitten by it. It only happens when you use a value returned from an included or required file. Let's say you have a file called fiddledata.php with this for the last line:

return 10;

In another file, you do this:

$x = include_once "fiddledata.php";
echo "\nX = " . $x;

/* Output:
    X = 10
/*

So far, so good. The value returned from the included file is echoed correctly. Now we try this:

$x = include_once "fiddledata.php";
echo "\nX = " . $x;

$x = include "fiddledata.php";
echo "\nX = " . $x;

/* Output:
    X = 10
    X = 10
*/

We're still good. The return value is echoed both times.

How about this?

$x = include_once "fiddledata.php";
echo "\nX = " . $x;

$x = include_once "fiddledata.php";
echo "\nX = " . $x;

/* Output:
    X = 10
    X = 1
*/

Oh, oh. What happened? When PHP sees the include_once the second time, it knows the file has already been included. It won't include it again. Instead, it returns TRUE to indicate that the "include" was successful. The echo statement displays TRUE as a number 1.

In the section above, everything we've seen would also be true if we used "require" instead of "include."

A common use of include or require is to include a class file that returns the class name. For example, the login controller contains this line:

$className = include_once $processorFile;

The processor file contains the processor class, and it returns the name of the processor class. If this code were run twice, the second time the name of the processor class would be 1 which would cause serious trouble when the code tried to instantiate that non-existent class.

Here's another example. The version file for MODX contains an array containing parts of the current version. The MODX class file contains this function that gets the current version:

public function getVersionData() {
        if ($this->version === null) {
            $this->version= @ include_once MODX_CORE_PATH . "docs/version.inc.php";
        }
        return $this->version;
}

The version file returns an array containing information about the current version. Notice the if statement. The version file is only included if $this->version === null. That makes sure that the include_once will never execute twice. If it did, the second time the version data would be the number 1 instead of the array.

It's important to keep this in mind when using the return value from an included or required file. In that case, having the ..._once code execute twice can result in a crash that will come with an extremely unhelpful error message that makes the problem very difficult to diagnose.

Coming Up

The include_once or require_once solution we discussed 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 you, or the developer, to put the function inside a class. We'll see how to do that in the next article.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.