Calling Constructors

Take a look at this code, found inside the Jetpack Post Views plugin:

function Jetpack_Post_Views() {
  $this->__construct();
}

Here an object is calling its own constructor. But what’s wrong with it?

The General rule for calling __construct:

The only occasion it is okay to call a constructor method directly, is in a child class that needs to call its parent constructor

Calling a constructor method this way is heresy of the highest order in programming, and it is a rare occasion that it is valid, or that the programming language even allows it.

But What Could Go Wrong?

Sure it’s not the best but better to be safe than sorry? Lets carry on and when we need to change, lets change

– someone who later went out of business

Constructors are not ordinary methods, they are ran when an object is created. Calling a constructor is something that happens as part of the language, and as such has special considerations. This is true of most programming languages, not just PHP. It can cause a lot of problems.

For example, the following in C++ will cause compile errors:

Foo foo;
foo.Foo();  // compile error!

It also indicates that the constructor of the object does work/heavy lifting. Constructors are not supposed to do heavy lifting, they initialise the basics, such as default values. An object that prints out data when constructed, makes connections, or writes files, is doing too much.

If real work is needed in the constructor other than setting up internal placeholder data structures, then it needs to be done elsewhere and passed in as a constructor parameter, or refactored out into a method ( e.g. a connect or open method ).

Object creation can become costly if this isn’t done, generating performance slowdowns, and code that’s difficult to test and document.

The only valid situation to call an objects constructor, is when already inside a constructor, in a subclass, and the parent constructor needs to take different arguments. E.g:

class Foo extends Bar {
    public function __construct( $args ) {
        parent::__construct( array( 'different', 'arguments') ); // call the Bar constructor
        // do Foo specific things
    }
}

Here the Foo class does work, but it calls the Bar constructor beforehand. It does this because they take different arguments. Notice the use of parent:: and not $this->.

Any situation that requires a call to a constructor other than the above that isn’t the use of the new keyword, is wrong. The same is true of calls to __destruct.

Even in this case however, we have a problem. In this example, Foo objects and Bar objects know too much about each other and are too tightly coupled. The work that’s done in the Bar constructor that the Foo constructor needs to redo but with different arguments, should be in a different method, or the arguments provided by another means.

So How Do I Correct This?

Refactor the code in your constructor out into its own method/object. Your constructor is doing work that it shouldn’t, and you need to enforce separation of concerns. Examples include init methods, or doing work only when it’s needed rather than on object creation.

For example, a few of my own plugins have a run method. This allows me to create a plugin object, insert some test data, and run my code when I choose. By doing this, creating my plugin, and executing it have been separated out.

In other situations, e.g. my object needs to read and write from a file to do its work, I separated the file IO out into a new object, and passed that to my object as a constructor argument. This way I can initialise Filesystem access separately, then pass it to my object during initialisation. This also leaves the door open to alternative implementations such as database access.

Further Reading

2 thoughts on “Calling Constructors

  1. Tom,
    Isn’t this just Jetpack supporting an older version of PHP?

    In PHP V4, you create a constructor by declaring a method with the same name as that of the class. In V5, you should declare a method called __construct().

    So it seems to me if Jetpack runs on PHP V4, the method you mention will get called which will then call the ‘real’ constructor. On V5 the real constructor will get called directly.

    I’ve written this type of code myself.

    Mike

    • There are plenty of people who do it for non-PHP 4 reasons because their constructors do too much, this example is probably an artefact from an earlier version of the jetpack views plugin

Leave a Reply

Your email address will not be published. Required fields are marked *