How can I create a class with a given array of arguments to be sent to the constructor? Something along the lines of:
class a {
var $args = false;
function a() {$this->args = func_get_args();}
}
$a = call_user_func_array('new a',array(1,2,3));
print_r($a->args);
Ideally this needs to work, without modification to the class, in both PHP4 and PHP5. Any ideas?
ReflectionClass:newInstance() (or newInstanceArgs()) let's you do that.
e.g.
class Foo {
public function __construct() {
$p = func_get_args();
echo 'Foo::__construct(', join(',', $p), ') invoked';
}
}
$rc = new ReflectionClass('Foo');
$foo = $rc->newInstanceArgs( array(1,2,3,4,5) );
edit: without ReflectionClass and probably php4 compatible (sorry, no php4 at hand right now)
class Foo {
public function __construct() {
$p = func_get_args();
echo 'Foo::__construct(', join(',', $p), ') invoked';
}
}
$class = 'Foo';
$rc = new $class(1,2,3,4);
speed comparison:
Since the speed of reflection has been mentioned here's a little (synthetic) test
define('ITERATIONS', 100000);
class Foo {
protected $something;
public function __construct() {
$p = func_get_args();
$this->something = 'Foo::__construct('.join(',', $p).')';
}
}
$rcStatic=new ReflectionClass('Foo');
$fns = array(
'direct new'=>function() { $obj = new Foo(1,2,3,4); },
'indirect new'=>function() { $class='Foo'; $obj = new $class(1,2,3,4); },
'reflection'=>function() { $rc=new ReflectionClass('Foo'); $obj = $rc->newInstanceArgs( array(1,2,3,4) ); },
'reflection cached'=>function() use ($rcStatic) { $obj = $rcStatic->newInstanceArgs( array(1,2,3,4) ); },
);
sleep(1);
foreach($fns as $name=>$f) {
$start = microtime(true);
for($i=0; $i<ITERATIONS; $i++) {
$f();
}
$end = microtime(true);
echo $name, ': ', $end-$start, "\n";
sleep(1);
}
which prints on my (not so fast) notebook
direct new: 0.71329689025879
indirect new: 0.75944685935974
reflection: 1.3510940074921
reflection cached: 1.0181720256805
Isn't that bad, is it?
Have a look at the Factory Method pattern and check out this example
From Wikipedia:
The factory method pattern is an
object-oriented design pattern. Like
other creational patterns, it deals
with the problem of creating objects
(products) without specifying the
exact class of object that will be
created.
If you don't want to use a dedicated Factory for this, you could still wrap Volker's code into a function, e.g.
/**
* Creates a new object instance
*
* This method creates a new object instance from from the passed $className
* and $arguments. The second param $arguments is optional.
*
* @param String $className class to instantiate
* @param Array $arguments arguments required by $className's constructor
* @return Mixed instance of $className
*/
function createInstance($className, array $arguments = array())
{
if(class_exists($className)) {
return call_user_func_array(array(
new ReflectionClass($className), 'newInstance'),
$arguments);
}
return false;
}