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
Differencebetween $_Files["File"]["Type"] and End(Explode(".", $_Files["File"]["Name"]))
Multiple Radio Button Array for PHP Form
Rewrite All Queries to Not Need the .PHP Extension Using a Mod_Rewrite Rewriterule
Pdoexception' with Message 'Sqlstate[22001]: String Data, Right Truncated: 0
Using Pdo Prepared Statement and Incrementing a Column Value
Phpmailer Attachment, Doing It Without a Physical File
Jquery UI Saving Sortable List
Php's Function to List All Objects's Properties and Methods
PHP for ; Foreach Variable Scope
PHP Variable Variables with Array Key
PHP 7 and Strict "Resource" Types
How to Select MySQL Query with Foreign Language
Serial Comm with PHP on Windows
Echo PHP Variable from JavaScript
Convert Hex to Ascii Characters
HTML Purifier: Removing an Element Conditionally Based on Its Attributes