init() or __contruct()

I did a Google search to find out factory drawbacks, but did not succeed. Please invest a few minutes to clarify what you meant by ‘not good’.

I’m willing to accept your decision without further questions if it is well reasoned. However, I can’t see any purpose why we should keep the existing instantiation process without considering alternatives.

If a factory method not only creates a new class but also configures it from an argument, you then have the ability to customize the configuration process. It also means that external classes know less about the components’ internals, which is always good, even if subclassing a component takes a bit longer.

Here’s an example of what I thought:




class CComponent

{

   protected function __construct()

   {

      // pre-initialization

   }


   public static function factory($config=null)

   {

      $class = new self;

      // do whatever configuration needs

      // a foreach might do so far


      // post init, or init as in current implementation

      return $class;

   }

}



Edit:

The only drawback I found (bug 30934):

Using the factory method, how would you write a child class that needs to do some initialization before parent’s initialization?

The "self" bug you mentioned is a big one. This can only be solved in PHP 5.3.

I needed to investigate first. Then experiment. I don’t know your code, and there are no tests, so it takes a lot more time than a well organised project. So I have to create tests, branch, and validate my ideas. That’s why I asked questions, to speed things along. I have no wish to rock the boat.

No problem. There are some unit tests under "tests" folder. They only cover part of the code. Adding more coverage of tests is one of the major tasks looking forward (mainly need to find good ways to set up different fixtures).

I apologize if my posts hurt you. I guess I am overheated.

This framework is far from perfect. There are many places that need to be improved. One of the biggest obstacles to these improvements is to maintain backward compatibility (BC). For this reason, I have to defend hard when a design change may break BC.

Having said that, I don’t mean we should sit on mistakes. We may take your suggestions when we do a major release or rewrite that doesn’t have keeping BC as top priority.

By extending constructor and calling parent implementation lastly.

Update:

Backward compatibility is definitely an important point of view, but as these ideas are really long term, I think they simply cannot be implemented before the next major version. But it’s fine.

Could you write some pseudo code to show this? Note that these initialization (both parent’s and child’s) need to be done after configuration.

Of course. Please note that prior to 5.3, PHP forces me to copy self-referential methods, which might turn the whole thing even more harmful than the current implementation. I can’t decide, though. I’m also not aware the possible workaround you mentioned regarding 5.3.




class CParent

{

   protected function __construct()

   {

      // before config

   }


   public function factory($config=null)

   {

      $class = new self;

      // config

      // ...

      return $class;

   }

}


class CChild extends CParent

{

   protected function __construct()

   {

      // before parent init

      parent::__construct();

      // after parent init

   }


   public function factory($config=null)

   {

      $class=new self;

      // config

      // ...

      return $class;

   }

}



Subclasses of CActiveRecord are required to have a model function to overcome this self issue. I know this is overwhelming.

If configuration is complex, we can dedicate a protected method for it. Otherwise it can be done in the constructor (which won’t make that ‘a big black box’). So only factory($config=null){return new self($config);} would be necessary in each descendant.

Nope, your code doesn’t meet the requirement. I was saying the init code is needed after the configuration is applied (e.g. establishing DB connection after the connection parameters are set).

I’m not at all offended. No pasa de nada.

Sure. Completely understood.

BC (and regresion, of course) was also one of the issues I was considering, which is why I needed good test coverage of the areas I was looking at. That’s not a ten minute job!

No problem,

w000000t, I was so happy ready this, and all of the sudden it stops? I deserve a conclusion!

:lol: so what 's your conclusion ?

Found a great use for having both __construct() and init() for CPortlet. I have a javascript library that I need to add to all pages on a client’s site, and for one view, a property of this CPortlet has a different specified value than any other view. I also have a need to override this value under certain conditions.

The class that Ive extended CPortlet has a property initialized to FALSE. During its __construct(), Ive added some logic to determine if the portlet is called from one particular controller/action, and change the value of this property to TRUE. When the widget is called within my viewfile via:


<?php $this->widget('MyPortlet'); ?>

I can choose to override this property, since the logic discussed above is performed in __construct(), and more specifically, not done in init() :


<?php $this->widget('MyPortlet', array('myProperty' => TRUE)); ?>

I rarely will configure “MyPortlet” with that config, however, and prefer to just let the constructor logic determine the necessary conditions for changing ‘myProperty’ from FALSE to TRUE.

Im aware there are many ways to do this same thing, but I feel this is a tidy way to accomplish what I need.