views:

513

answers:

4

Please see the code bellow:

01. class Test {
02.     public function __construct($param1, $param2, $param3) {
03.         echo $param1.$param2.$param3;
04.     }
05. }
06. 
07. $params = array('p1','p2','p3');
08. 
09. $ob = new Test;
10. 
11. if(method_exists($ob,'__construct')) {
12.     call_user_func_array(array($ob,'__construct'),$params);
13. }

Now, the problem is the constructor is called in line 09

But i want to call it manually at line 11-13

Is it possible? If then how? Any idea please?

+12  A: 

It is not possible to prevent the constructor from being called when the object is constructed (line 9 in your code). If there is some functionality that happens in your __construct() method that you wish to postpone until after construction, you should move it to another method. A good name for that method might be init().

Why not just do this?

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }
}

$ob = new Test('p1', 'p2', 'p3');

EDIT: I just thought of a hacky way you could prevent a constructor from being called (sort of). You could subclass Test and override the constructor with an empty, do-nothing constructor.

class SubTest extends Test {
    public function __construct() {
        // don't call parent::__construct()
    }

    public function init($param1, $param2, $param3) {
        parent::__construct($param1, $param2, $param3);
    }
}

$ob = new SubTest();
$ob->init('p1', 'p2', 'p3');

This is might make sense if you're dealing with some code that you cannot change for some reason and need to work around some annoying behavior of a poorly written constructor.

Asaph
A: 

to construct your object first and then pass parameters your could try this way:

class Test {
    public function __CONSTRUCT($p1="Bundy", $p2="house", $p3=10) {
        $this->init($p1, $p2, $p3);
    }
    public function init($p1, $p2, $p3) {
        //setup your object here
    }
}

then it is possible to construct the object and call

$ob->init($p1, $p2, $p3);

later.

justastefan
This doesn't work because PHP doesn't support method overloading. This strategy would work in a language like Java.
Asaph
Yes, you're right. I removed the constructor overloading.. ... done too much java lately
justastefan
Ok, good edit but your `$ob->init($params);` doesn't look consistent with your definition of the `init()` function which accepts 3 arguments instead of a single array. BTW: There is no such thing as too much Java.
Asaph
Right, i edited again. i feel like learning with all these comments...
justastefan
+1  A: 

If separating instantiation from initialization isn't strictly a requirement, there are two other possibilities: first, a static factory method.

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }

    public static function CreateTest($param1, $param2, $param3) {
        return new Test($param1, $param2, $param3);
    }
}

$params = array('p1','p2','p3');

if(method_exists($ob,'__construct')) {
    call_user_func_array(array($ob,'CreateTest'),$params);
}

Or, if you're using php 5.3.0 or higher, you can use a lambda:

class Test {
    public function __construct($param1, $param2, $param3) {
        echo $param1.$param2.$param3;
    }
}

$params = array('p1','p2','p3');

$func = function ($arg1, $arg2, $arg3) {
    return new Test($arg1, $arg2, $arg3);
}

if(method_exists($ob,'__construct')) {
    call_user_func_array($func, $params);
}

The initialization method described by Asaph is great if for some reason you have a need to logically separate initialization from instantiation, but if supporting your use case above is a special case, not a regular requirement, it can be inconvenient to require users to instantiate and initialize your object in two separate steps.

The factory method is nice because it gives you a method to call to get an initialized instance. The object is initialized and instantiated in the same operation, though, so if you have a need to separate the two it won't work.

And lastly, I recommend the lambda if this initialization mechanism is uncommonly used, and you don't want to clutter your class definition with initialization or factory methods that will hardly ever be used.

Dathan
A: 

Note that if the constructor (__construct method) contains arguments passed by reference, then the function:

call_user_func_array

will fail with an error.

I suggest you to use Reflection class instead; here is how you can do so:

// assuming that class file is already included.

$refMethod = new ReflectionMethod('class_name_here',  '__construct');
$params = $refMethod->getParameters();

$re_args = array();

foreach($params as $key => $param)
{
 if ($param->isPassedByReference())
 {
  $re_args[$key] = &$args[$key];
 }
 else
 {
  $re_args[$key] = $args[$key];
 }
}

$refClass = new ReflectionClass('class_name_here');
$class_instance = $refClass->newInstanceArgs((array) $re_args);
Sarfraz