PHP Call_User_Func VS. Just Calling Function

PHP call_user_func vs. just calling function

Always use the actual function name when you know it.

call_user_func is for calling functions whose name you don't know ahead of time but it is much less efficient since the program has to lookup the function at runtime.

What scenario requires use of call_user_func() in php

I've had a couple situations where this was very necessary. For example, when I was creating a project that allowed a user to construct parts of a programming language, the system would wrap the "tag" definition in a function before running it for security reasons. However, in doing this, I can't simply call those functions, because I don't know when I need to call them, or even what the names would be. Enter call_user_func()...

So, I'm sure you're confused right now. Let me explain. What my system did, was take some XML, and convert it into PHP/HTML/JS with PHP. This allowed for rapid creation of GUIs (which was the goal). Take this XML for example:

<window id="login-win" title="Access Restricted" width="310" height="186" layout="accordion" layoutConfig="animate:true">
<panel id="login-panel" title="User Login">
<form id="login-form" title="Credentials">
<textbox id="login-uname" label="Username"/>
<password id="login-pass" label="Password"/>
<submit text="Login"/>
</form>
</panel>
<panel id="login-register" title="Register">
Nothing, you can't register!
</panel>
</window>

Each XML tag would be read, then fed into it's corresponding PHP function. That function would determine what to do for that 1 tag. In order to pull this off, I had files each named after the tag it handled. So, for example, the tag's file was "submit.php". This file's contents would get wrapped in a generated function, something like:

function tag_submit($variables, $parent, $children){

// deal with the data, then echo what is needed

}

This function's name would be stored in an array, with it's associated tag name, with the rest of the generated functions. This makes it so the function is generated once, and only created when needed, saving memory, since I would do a if(func_exists()) call to determine if I needed it or not.

However, since this is all dynamic, and the user may want to add in a new tag, for say, a < date > tag, I needed to use call_user_func() to get things to work. I can't hard-code a function call if I don't know what the name is.

Hope that all made sense. Basically, yes, it is a rarely used function, but it is still very very useful.

Php (eval vs call_user_func vs variable functions ...)

First of all, there's no need to pass references like you are doing. You should give this a read to try to understand how PHP handles object references.

So public function save(&$VO) { should become public function save($VO) {.

Second, there is no need to use eval (in fact, it's better not to because of speed, debugability, etc). You can't stack-trace an eval call like you can a dynamic one.

Third, call_user_func is all but useless since PHP supports dynamic variable functions. Instead of call_user_func(array($obj, $method), $arg1), just call $obj->$foo($arg1). The call_user_func_array function is still useful since it supports variable length arguments and supports passing references.

So, ultimately, I would suggest this:

$method = 'get' . ucfirst($paramIdArray[1]);
$voId = $VO->$method();

Note that there's no need to call method_exists, since it may be callable and not exist due to __get magic method support...

Difference between calling a Closure in Class via call_user_func and ::call

https://www.php.net/manual/en/closure.bindto.php#refsect1-closure.bindto-parameters

bindTo accepts 2 parameters:

  1. the object to bind to
  2. the newScope to apply to that object. If you don't supply the 2nd argument then the default, static scope, is applied. If you pass through a string (the class name) or an object and then your closure will be scoped to that object.

The class scope to which associate the closure is to be associated, or
'static' to keep the current one. If an object is given, the type of
the object will be used instead. This determines the visibility of
protected and private methods of the bound object. It is not allowed
to pass (an object of) an internal class as this parameter.

<?php
...

// Pass an object through as 2nd argument.
return call_user_func($this->routes[$this->requestUri]['cb']->bindTo($this, $this));

// Pass the class name (string) through as 2nd argument.
return call_user_func($this->routes[$this->requestUri]['cb']->bindTo($this, 'Router'));

why should one prefer call_user_func_array over regular calling of function?

  1. You have an array with the arguments for your function which is of indeterminate length.

    $args = someFuncWhichReturnsTheArgs();

    foobar( /* put these $args here, you do not know how many there are */ );

    The alternative would be:

    switch (count($args)) {
    case 1:
    foobar($args[0]);
    break;
    case 2:
    foobar($args[0], $args[1]);
    break;
    ...
    }

    Which is not a solution.

The use case for this may be rare, but when you come across it you need it.

When to use call_user_func_array

An example of where call_user_func_array is very useful

Lets say you have a desire to access an object, but through static methods, like this:

Helper::load();

Well, that won't work by itself, because if you look at the concrete class it doesn't have the static method:

class Helper {

public function load()
{
// Do some loading ...
}

public function aFunctionThatNeedsParameters( $param1, $param2 )
{
// Do something, and $param1 and $param2 are required ...
}
}

So in a second class, we could do something like this, because the Helper class above is loaded into a dependency injection container (note that these two Helper classes are named the same, but would be in different namespaces):

class Helper extends DIContainer {

public static $helper_instance = NULL;

public static function get_instance()
{
if( is_null( self::$helper_instance ) )
{
self::$helper_instance = parent::$container['helper'];
}

return self::$helper_instance;
}

public static function __callStatic( $method, $params )
{
$obj = self::get_instance();

return call_user_func_array( [ $obj, $method ], $params );
}
}

The thing is, there may be another method that needs parameters, even though our load method doesn't have any.

So in this case we can use Helper::load(), but also Helper::aFunctionThatNeedsParameters( $param1, $param2 )

I think this is used a lot in PHP frameworks that know that static classes are not usually appropriate, but they want the ability to call methods as if they were static. I hope this makes sense.

call_user_func vs variable variables in PHP

Your example lacks clarity.

Normally it's better to have some understandable code:

$callback = array($this, $method):

if (is_callable($callback)) {
call_user_func($callback);
}

However depending on taste, you might prefer:

if (is_callable($callback)) {
$callback();
}

I wouldn't favor the one over the other but take the one that works.

That being said I would strongly try to not make use of magic at such a point and I personally prefer to call explicitly defined methods by their defined name and not by variable. Just to not introduce hard to debug magic.

PHP forward_static_call vs call_user_func

The difference is just that forward_static_call does not reset the "called class" information if going up the class hierarchy and explicitly naming a class, whereas call_user_func resets the information in those circumstances (but still does not reset it if using parent, static or self).

Example:

<?php
class A {
static function bar() { echo get_called_class(), "\n"; }
}
class B extends A {
static function foo() {
parent::bar(); //forwards static info, 'B'
call_user_func('parent::bar'); //forwarding, 'B'
call_user_func('static::bar'); //forwarding, 'B'
call_user_func('A::bar'); //non-forwarding, 'A'
forward_static_call('parent::bar'); //forwarding, 'B'
forward_static_call('A::bar'); //forwarding, 'B'
}
}
B::foo();

Note that forward_static_call refuses to forward if going down the class hierarchy:

<?php
class A {
static function foo() {
forward_static_call('B::bar'); //non-forwarding, 'B'
}
}
class B extends A {
static function bar() { echo get_called_class(), "\n"; }
}
A::foo();

Finally, note that forward_static_call can only be called from within a class method.

call_user_func_array vs. call_user_func

I have had issues like this that came down to __autoload not firing properly when a not-yet-loaded class was invoked through a PHP command. No other strategy than dumb trial and error for it as far as I know, just try if a line explicitly invoking the class before the PHP command solves it for you.

$dummy = new MyClassName;
call_user_func_array(array('MyClassName', 'method'), array($id));
unset($dummy);


Related Topics



Leave a reply



Submit