I am trying to call a class' constructor through a callable, so I had the following code:
$callable = array('Foo', '__construct');
However calling this will throw the following error:
Fatal error: Non-static method Foo::__construct() cannot be called statically
I understand that the constructor is not a static method, but I can't use an existing instance to call the constructor for a new instance (as it will just call the constructor on the existing object again), is there any way at all to call a constructor like this?
If you really have to use call_user_func
, this might work, though it's not clear why you would want to do this:
$reflection = new ReflectionClass("Foo");
$instance = $reflection->newInstanceWithoutConstructor();
call_user_func(array($instance, '__construct'));
If you're looking for a simple way to dynamically choose which class to construct, you can use a variable name with the new
keyword, like so:
$inst = new $class_name;
// or, if the constructor takes arguments, provide those in the normal way:
$inst = new $class_name('foo', 'bar');
However, if what you need is a way of passing the constructor to something which is already expecting a callable, the best I can think of is to wrap it in an anonymous function:
$callable = function() { return new Foo; }
call_user_func( $callable );
The more correct answer, as @MauganRa already mentioned in a comment, is using \ReflectionClass::newInstance()
or \ReflectionClass::newInstanceArgs()
. I think this should be expressed in a full answer.
Now if you want to pass this around as a callback and use call_user_func()
or call_user_func_array()
, try this:
$callable = [new \ReflectionClass('C'), 'newInstance'];
Or a more fleshed-out example:
class Car {
private $color;
private $size;
public function __construct($color, $size) {
$this->color = $color;
$this->size = $size;
}
public function describe() {
return "A $this->size $this->color car.";
}
}
$callable = [new \ReflectionClass('Car'), 'newInstance'];
$cars = [];
$cars[] = call_user_func($callable, 'red', 'big')->describe();
$cars[] = call_user_func_array($callable, ['blue', 'small'])->describe();
var_export($cars);
Demo: https://3v4l.org/7fvQL
I am not aware of another / better solution.