Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 307
GordonM Avatar asked Nov 21 '11 10:11

GordonM


2 Answers

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.

like image 200
Frosty Z Avatar answered Sep 24 '22 01:09

Frosty Z


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.

like image 29
Gordon Avatar answered Sep 23 '22 01:09

Gordon