Fatal Error cannot redeclare function Part 2

Solving function name collisions by putting functions inside a class.

By Bob Ray  |  November 26, 2024  |  6 min read
Fatal Error cannot redeclare function Part 2

In the previous article, we saw how to prevent an error like this one by wrapping the function in an if (! function_exists() statement or only including the file with function once.

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 a better method of avoiding that error: putting the function inside a class.

The Problem

As we saw in my previous article, 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. We've changed the name of the function here from add() to addIntegers(). This is a good coding practice, not only because it helps prevent collisions with other functions named add(), but also because the name of the function better describes what the function actually does. This will come in handy when you're looking at your code down the road and see that function called.

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

As we saw in the previous article, PHP won't let you declare the function more than once. If the code is used more than once on a page, PHP will throw a fatal error. In that article, we saw a quick solution that looked like this:

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

A Better Method

Suppose someone else's code on the same page also has a function called addIntegers(). If the other developer has not wrapped the function as we did, PHP will still throw a fatal error if our code is called first. If our code is called second, or if the other developer has also wrapped the function, things are even worse. Our code might end up using the other developer's function instead of our own, or vice versa.

If the two functions are different, this could be disastrous. Suppose the two functions add records to different parts of the database. In the worst case scenario, they would both work, but add the data to the wrong table. It might go unnoticed for a while and would be a nightmare to correct.

A much more robust, and infinitely safer, solution would be to put the function inside a class. This is not a quick solution for cases where a developer has forgotten to wrap a function. It's a suggestion for developers who want their code to play nice with the code of others.

Classes

A class in PHP is an object that "encapsulates" functions and variables. Functions inside classes are usually referred to as "methods" to distinguish them from standalone functions, and we'll use that term from here on. They're still functions, but they can only be called via the class they are declared in.

This is all much simpler than it sounds.

Putting our Function in a Class

In this example, we'll add a subtractIntegers() method so you can see a class with multiple methods. To put our method inside a class, all we need to do is this:

class MyMathFunctions {
    public function addIntegers($a, $b) {
        return $a + $b;
    }

    public function subtractIntegers($a, $b) {
        return $a - $b;
    }
}

Now, our addIntegers() function is a method of the MyMathFunctions Class. When we want to use it, we need to create an object of the class (the technical term is "instantiate"), and call our method. That looks like this:

$math = new MyMathFunctions();
echo $math->addIntegers(2,3);
/* Displays 5 */

Our subtractIntegers() method would be called the same way. Once you've instantiated the MyMathFunctions object, any of its methods can be called using className->methodName().

The variable, $math is arbitrary, you could use any variable name here. It's technically described as an "instance" of the MyMathFunctions object. Since it has the addIntegers() method, we can call that method as many times as we like. More important, the method can only be called through the class object, using the -> operator. No one can call our method without first intentionally instantiating the MyMathFunctions object, so collisions are extremely unlikely, no matter what the method (function) is called. If someone else has an addIntegers() method. They can call it with no chance of our method being called and no potential for the PHP fatal error.

Another advantage of using classes is that the class code, like that of our MyMathFunctions class, is usually put in another PHP file, separate from any code that calls its methods. This makes it more secure. If someone manages to access the class file, it will execute, but it won't actually do anything. Typically, our the code in the example just above would look like this:

include 'mymathfunctions.class.php';

$math = new MyMathFunctions();
echo $math->addIntegers(2,3);
/* Displays 5 */

Our MyMathFunctions class code would be in the mymathfunctions.class.php file. Because MODX executes code via the index.php file, you need to include a full path to any included files, so the code above would more likely look like this:

include MODX_CORE_PATH . 'components/mycomponentname/model/mymathfunctions.class.php';

$math = new MyMathFunctions();
echo $math->addIntegers(2,3);
/* Displays 5 */

We've declared our addIntegers() method as public. That means the method can be called from outside the class as in the example above. Methods can also be declared as private or protected. Private methods can only be called from within the class itself (in other words, only by other methods in the class). Protected methods can only be called from within the class or from within descendants of the class. Our method needs to be public because we need to call it from outside the class.

Coming Up

By putting our methods inside a class, we've prevented the fatal error about re-declaring a function that occurs when the code is used more than once on a page. We've also pretty much eliminated the issue of other code containing functions with the same name. We have a new problem, however. Like functions, classes also can't be redeclared in PHP. If our class code is 'included' more than once, will produce another fatal error. We'll look at solutions for preventing 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.