Best practice, overriding __construct() versus providing init() method

23,013

Solution 1

Looks like the second approach is postponing the problem.

If you have a class:

class bar2 extends bar // which already extends foo
{
  public function init()
  {
    // You should then do anyway:
    parent::init();

    // ...
  }
}

I would go for the first approach too, more logical and straightforward, since the parent::init() or parent::__construct() call could not be endlessly avoided. The first approach, IMO, is less confusing.

Solution 2

The only two situations I can think of in which it makes sense to use init() is when your constructor is non-public but you need to give people a chance to influence initialization, e.g. in an abstract Singleton (which you do not want to use anyway). Or, like in Zend Framework, when additional initialization should be defered (but then you don't call init() from the constructor).

Calling a method in a subclass from the superclass is called Template Method, by the way. The UseCase would be to orchestrate a certain workflow but allow the subtype to influence parts of it. This is usually done from regular methods though. Note that your constructor should not orchestrate anything but just initialize the object into a valid state.

You definitely should not call/offer init() from the constructor to prevent developers having to remember to call the supertype constructor. While that may sound convenient, it will quickly mess up the inheritance hierarchy. Also note that it deviates from how objects are usually initialized and developers have to learn this new behavior just like they have to learn to call the supertype's constructor.

Solution 3

Firstly

Zend also tends to do a few things that I'm not happy with

You can solve this simply, by not using it.

But secondly and more importantly you should override init() and not __construct() because init() is part of the dispatch operation that Zend uses and using it ensures that the rest of your App is there and in place. Doing otherwise breaks the flow of Zend's MVC model and may result in odd behaviour.

Edit

I think the main reason for me is that it stops other developers from fiddling. You can do anything with init() but not with __construct() as this needs to run correctly with all the correct params in place.

This is from the Zend Docs:

While you can always override the action controller's constructor, we do not recommend this. Zend_Controller_Action::_construct() performs some important tasks, such as registering the request and response objects, as well as any custom invocation arguments passed in from the front controller. If you must override the constructor, be sure to call parent::_construct($request, $response, $invokeArgs).

Solution 4

I would use the init function because if you override the constructor you (normally) have to remember to call the parent constructor at the top of your child class's constructor. While you may be aware of that, you can not guarantee that another developer tasked with maintining your application will be.

Share:
23,013
GordonM
Author by

GordonM

I'm a professional PHP programmer with almost a decade of professional experience and considerably more as a hobbyist programmer. I've also had some exposure to Java, Object Pascal and am interested in learning objective C I've started work on a PHP framework, though it's still at a very early stage and not yet really useful. The current source is available on GitHub. I've also begun development of a CSS3 elastic grid for use on my own projects and had published that on GitHub as well.

Updated on June 09, 2020

Comments

  • GordonM
    GordonM almost 4 years

    When you are subclassing objects and want to extend the initialization code, there are two approaches. Overriding __construct(), and implementing an initialization method that your superclass constructor calls.

    Method 1:

    class foo
    {
        public function __construct ($arg1, $arg2, $arg3)
        {
            // Do initialization
        }
    }
    
    class bar extends foo
    {
        public function __construct ($arg1, $arg2, $arg3)
        {
            parent::__construct ($arg1, $arg2, $arg3);
            // Do subclass initialization
        }
    }
    

    Method 2

    class foo
    {
        public function init ()
        {
            // Dummy function
        }
    
        public function __construct ($arg1, $arg2, $arg3)
        {
            // Do subclass defined initialization
            $this -> init ();
            // Do other initialization
        }
    }
    
    class bar extends foo
    {
        public function init ()
        {
            // Do subclass initialization
        }
    }
    

    The documentation for Zend Framework seems to discourage overriding constructors and wants you to override init methods, where provided, but this somehow just doesn't feel right to me. Zend also tends to do a few things that I'm not happy with so I'm not sure if it should be used as an example of best practice. I personally think the first approach is the correct one but I've seen the second approach often enough to wonder if that's actually what I should be doing.

    Do you have any comments regarding overriding __construct? I know you have to be careful to remember to invoke the superclass constructor, but most programmers should be aware of that.

    EDIT: I'm not using Zend, I'm only using it as an example of a codebase that encourages you to use init() instead of overriding __construct().