Fatal Error Cannot Redeclare Function II

Putting our function inside a class to avoid collisions


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

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: putting the function inside a class.


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. 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 in the same way.

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. 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.

In the MODX core, most methods are declared as public, even if they're only intended to be called from within a class. This is done because it makes the classes easier to test with PHP unit tests. It's not universal, but most methods in MODX that are intended to be called only from within the class are prefixed with an underscore like this: _methodName(). They are declared as public, but it's generally a bad practice to call those methods in your own code.


Coming Up

By putting our methods inside a class, we've prevented the fatal error about redeclaring 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.



Comments (2)

  1. MellFotoStudioFeb 25, 2016 at 07:32 AM

    A very good day to you, fine Sir! I see you've written a new article, and well-written it is.

    I do however have a few points I'd like to dispute. And so, in order of appearance...


     
    "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."

    Actually, when you put a function in like that, you're both declaring and defining the function. A definition, by its virtue, is also a declaration - but not the other way around.

    A declaration states what the function's handle (eg. name) will be, what it will take as parameters, and what its return type will be (if applicable).

    A definition provides the same information and also explains in detail what the function will actually do (ie. defines its code).

    As such, I believe the safer word to use there is "defining", esp. if you'd like to delve deeper into class construction – understanding the subtleties of this will come in handy when dealing with extending abstract classes and building interfaces.


     
    "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."

    In principle – yes. In PHP practice – Your example is somewhat misleading in that PHP does not actually concern itself with basic variable types at all*. What PHP will do is convert (cast) both values into a representation that will retain the most information, do the operation, and return the result in that "most information" form. For instance adding an int to a float is as valid as adding two ints - the int will be cast to float, the addition will be carried out on two floats, and a float will be returned**. This conversion is silent and typically doesn't trip anything up.

    It becomes an issue when doing comparisons, however, because "FALSE" and "0" are treated equally for comparison purposes, unless strict comparison (ie. the === operator) is used.

    Keep in mind that some functions usable for conditionals return FALSE for failure, but can also return 0 as a success value (strpos is one example).
    This behavior of PHP should always be kept forefront due to the security concerns it raises.

    A better function name I would propose would be:

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


    Keep in mind that this move still doesn't influence PHP in any way – it only states our intention as programmers, as to what the function does and should be used for. I can still ask it to add two strings, and while the operation is nonsensical from a sapient standpoint, PHP will still happily carry the operation out for me***.

    And I strongly feel that what "addIntegers" implies would do very little for someone who doesn't know other programming languages, but would confuse the crap out of anyone that do.


     
    "When we want to use it, we need to create an object of the class (the technical term is "instantiate"), and call our method."

    Um... no, you actually don't. Put the method in as a static method - it will keep all of the safeness of putting it in a namespace-like construct, but without actually having to lug around a hefty object instance, like so:

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

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

    and then call it like this:

    echo MyMathFunctions::addNumbers(2, 3);
    /* Displays 5 */

    I feel that it's much more to the point, since our original objective was to abstract the function in a toolkit, so we can do away with creating superfluous instances of stuff. Occam's razor.


    Footnotes:
    * Now, PHP does know C-types of its variables - it has to, because all calculations are actually done in C, which is strongly typed. What PHP does is keep the values as something else altogether, and then casts these values according to the required result. In other words, PHP infers what the programmer intends to do, and for the most part it works out great. In outlier cases, there are methods to override PHP's guesswork (especially, C-style casting is also a possibility), so it's all good.

    ** This behavior results from the fact that PHP is what is known as a weakly typed language (doesn't concern itself with variable types much) – but it is built on top of C, which is a strongly typed language (is religious about variable types). This means that in PHP adding an int to a float is not an issue, because both are numerical values. In contrast, with C such an addition is outright impossible without implicitly stating what you actually mean to do, and what you expect to receive as a result, because the operations will actually be different.

    *** This is also known as the GIGO Principle: Garbage In — Garbage Out. What it basically says is that as long as you provide parameters that are semantically valid, the operation will be performed regardless of the actual values being nonsensical (or not). For example, echo "A" + "B"; is a valid PHP operation because both letters are values as well — and it will return 0, which is probably not what you'd expect or want. Computers don't have understanding, it's up to us (programmers) to determine what is garbage in each context, and to then throw it away.

  2. Bob RayApr 02, 2016 at 03:42 PM

    I don't have any significant disagreements with you, but finer points like the difference between declaring and defining, the consequences of PHP's weak typing, the use of static and anonymous functions, abstract classes and methods, and interfaces, are far beyond the scope of this post.

    I use all of these methods in my code, but my primary audience is MODX users, many of whom are designers, not developers. A lot of them are just beginning to venture into PHP-land and I'm making an effort not to overwhelm them.


Please login to comment.

  (Login)