Is There a Call_User_Func() Equivalent to Create a New Class Instance

Is there a call_user_func() equivalent to create a new class instance?

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?

How to call the constructor with call_user_func_array in PHP

You can use reflection like:

$reflect  = new ReflectionClass($class);
$instance = $reflect->newInstanceArgs($args);

As of PHP 5.6.0, the ... operator can also be used for this purpose.

$instance = new $class(...$args);

if(version_compare(PHP_VERSION, '5.6.0', '>=')){
$instance = new $class(...$args);
} else {
$reflect = new ReflectionClass($class);
$instance = $reflect->newInstanceArgs($args);
}

PHP Call a instance method with call_user_func within the same class

The code you posted should work just fine. An alternative would be to use "variable functions" like this:

public function foo($method)
{
//safety first - you might not need this if the $method
//parameter is tightly controlled....
if (method_exists($this, $method))
{
return $this->$method('Hello World');
}
else
{
//oh dear - handle this situation in whatever way
//is appropriate
return null;
}
}

Java equivalent of PHP's call_user_func()

In java you should use reflection.

official documentation: http://docs.oracle.com/javase/tutorial/reflect/index.html

your case could look like this:

Class<?> c = Class.forName("foo");
Method method = c.getDeclaredMethod ("bar", new Class [0] );
method.invoke (objectToInvokeOn, new Object[0]);

where objectToInvokeOn is the instance/object (of class foo) you want to call on. In case you have it.

Otherwise you should go for:

Class<?> c = Class.forName("foo");
Object objectToInvokeOn = c.newInstance();
Method method = c.getDeclaredMethod ("bar", new Class [0] );
method.invoke (objectToInvokeOn, new Object[0]);

Using call_user_func() with objects

The two calls are not the same. You are calling:

return GeneralToolkit::retrieveByPK(array($comment->getItemId());

So of course you get a different answer. This is the correct code:

return call_user_func(array($peer, 'retrieveByPK'), $comment->getItemId());

Unless 'retrieveByPK' is static, but in that case you should use one of these calls (these all do the same thing):

return call_user_func(
get_class($peer) . '::retrieveByPK',
$comment->getItemId());

return call_user_func(
array(get_class($peer), 'retrieveByPK'),
$comment->getItemId());

return call_user_func_array(
get_class($peer) . '::retrieveByPK',
array($comment->getItemId()));

return call_user_func_array(
array(get_class($peer), 'retrieveByPK'),
array($comment->getItemId()));

So in that case your error was in using array() while calling call_user_func() instead of call_user_func_array().

Explanation:

Classes have two main types of functions: static and non-static. In normal code, static functions are called using ClassName::functionName(). For non-static functions you need first to create an object using $objectInstance = new ClassName(), then call the function using $objectInstance->functionName().

When using callbacks you also make a distinction between static and non-static functions. Static functions are stored as either a string "ClassName::functionName" or an array containing two strings array("ClassName", "FunctionName").

A callback on a non-static function is always an array containing the object to call and the function name as a string: array($objectInstance, "functionName).

See the PHP Callback documentation for more details.

PHP - how do I pass args to a class constructor while using variable class name?

$className = 'varClassName';
$validator = new $className(array('min'=>2, 'max'=>50));

How can I call a class with variables from array php?

You can use reflection for it:

$refClass = new ReflectionClass('SomeClass');
$instance = $refClass->newInstanceArgs($args);

Initiate object through an array

If there is no further dependencies to these object, you can simply do

$className = $object->type;
$instance = new $className;

If you need more sophisticated creation logic, you can put the creation code in Lambdas and call those then, e.g.

$allTypes = array(
'text' => function($string) { return new Text($string); },
'Image' => function($path) { return new Image($path); }
);
$instance = call_user_func_array($allTypes[$object->type], array($argument1));

Or you create a Factory object and put a switch/case into it:

class Factory
{
public function create($type)
{
switch ($type)
{
case 'text':
return new Text;
case 'image':
return Image($this->create('foo'));
case 'foo':
return new Foo;
default:
throw new Exception('No clue what to create');
}
}
}

Also checkout Is there a call_user_func() equivalent to create a new class instance?

Dynamically call Class with variable number of parameters in the constructor

You can do the following using ReflectionClass

$myClass = '\Some\Dynamically\Generated\a';
$myParameters = array ('dynamicparam1', 'dynamicparam2');

$reflection = new \ReflectionClass($myClass);
$myClassInstance = $reflection->newInstanceArgs($myParameters);

PHP manual: http://www.php.net/manual/en/reflectionclass.newinstanceargs.php

Edit:

In php 5.6 you can achieve this with Argument unpacking.

$myClass = '\Some\Dynamically\Generated\a';
$myParameters = ['dynamicparam1', 'dynamicparam2'];

$myClassInstance = new $myClass(...$myParameters);

call_user_func with parent method in child method

You've correctly identified that this code:

call_user_func (array($this, 'parent::f'));

When run in the context of C will keep calling B::f because $this will always be an instance of C and the parent of C is always B.

To fix it you can simple do:

call_user_func('parent::f');

It has no reference to the calling class, so it will resolve the parent class properly.

Out of the working alternative you have provided, the following is the better one:

call_user_func (array(__CLASS__, 'parent::f'));

This is because __CLASS__ always refers to the class declaration in which it appears and so will always be B.



Related Topics



Leave a reply



Submit