5

I've read other answers on stack pertaining to using call_user_func_array vs just calling the function but I still can't glean when the former should be used. I get that you might want to use call_user_func_array when you don't know how many args are passed thus you can do: $args = func_get_args(); ... but don't you always need to know the arguments if they are to be used in a function?

Both of the following work, I assume the first has less overhead.

$format = new Foo;
$method = 'somemethod';
$arg = 'somevalue';
if (method_exists($format, $method)) {
    return $format->$method($arg);
}

vs

return call_user_func_array(array($format, $method), array($arg));

When will one really benefit from using call_user_func_array?

5
  • I've seen and used it in static classes where an instance of a concrete class has been imported, and it is desired to access the concrete class through static methods. Commented Dec 24, 2017 at 20:17
  • when your PHP version does not support stored function name calls (5.4?). also func_get_args is often used when variadics does not supported (5.6). however i've seen so far its a matter of preference. being consistent is the key. Commented Dec 24, 2017 at 20:23
  • Now with argument unpacking it kinda makes this function mute, as that was the argument in answers here: stackoverflow.com/questions/18526060/… suppose it just comes down to if you want to support old php versions. Commented Dec 24, 2017 at 20:24
  • @Chay22 what exactly is a "stored function name calls"? Commented Dec 24, 2017 at 20:28
  • @Alex php.net/manual/en/functions.variable-functions.php Commented Dec 24, 2017 at 20:31

5 Answers 5

3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Interesting! Why would you desire to call a non-static method as static .. does it have something to do with the dependency injection?
Consider Laravel, arguably the most popular PHP framework, and they call these "Facades", laravel.com/docs/5.5/facades . They say the benefit is " providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods." And yes, this does have to do with dependency injection.
so basically, it, among other things, looks nicer
I suppose. One benefit of calling the static way would be that you don't have to maintain a chain of dependency injection through what is sometimes a bunch of classes.
2

David Sklar addressed the question of when to use call_user_func_array in his PHP Cookbook. So, to focus on one comment of the OP:

"...don't you always need to know the arguments if they are to be used in a function?"

Here's an instance where call_user_func() can come in handy:

<?php

function Test(){
  $args = func_get_args();
  call_user_func_array("printf",$args);
}

Test("Candidates 2014: %s %s %s %s\n","Tom","Debbie","Harry", "Sally");
Test("Candidates 2015: %s %s\n","Bob","Sam","Sarah");

See live code

With the pair of call_user_func_array() and func_get_args(), the user-defined function Test() can take a variable number of arguments.

Also, useful for aggregating methods (see PHP Cookbook p208-210) as the following simplified example demonstrates:

<?php
class Address {
   protected $city;

   public function getCity() {
      return $this->city;
   }
   public function setCity($city) {
      $this->city=$city;
   }
}

class Person {
     protected $name="Tester";
     protected $address;

     public function __construct() {
            $this->address = new Address;
     }
     public function getName(){
            return $this->name;
     }
    public function __call($method, $args){
           if (method_exists($this->address,$method)) {
                return call_user_func_array( array($this->address,$method),$args);
           }
    }
}

  $sharbear = new Person;
  echo $sharbear->setCity("Baltimore");
  echo "Name: ",$sharbear->getName(),"\n";
  echo "City: ",$sharbear->getCity();

See live code

Addendum

Since PHP 5.6, PHP supports variadic functions and argument unpacking, so call_user_func() and func_get_args() may be replaced with respect to variable arguments as follows:

<?php

function Test(...$args){

   printf(...$args);
}
$namesT = ["Timmy","Teddy","Theo","Tad"];
$namesB = ["Bobby","Bill","Brad"];

Test("T Names: %s %s %s %s\n",...$namesT);
Test("B Names: %s %s %s\n",...$namesB);

See live code

Comments

2

<!-- begin snippet: js hide: false console: true babel: false -->

<pre>
I use call_user_func_array when I need to call a function or php function from my ajax enabled page. 

eg.
in html and javascript:

<form id='my-form'>

<input id='name' value='Wong, Billy'>
<input id='age' value='50'>

<a href='javascript;' onClick="xjx.query('helloWorld', $('#name').val(), $('#age').val())">Show name and age</a>

<a href='javascript;' onClick="xjx.query('showName', $('#name').val())">Show name</a>

<a href='javascript;' onClick="xjx.query('showAge', $('#age').val())">Show age</a>

<a href='javascript;' onClick="xjx.post('#my-form', 'showPost', 'live long and prosper')">Show age</a>

</form>

xjx.query and xjx.post, personal javascript functions of mine will then format and submit to the php page via ajax

in php
$method = $_POST['method'];
$args = $_POST['args'];

call_user_func_array($method, $args)

function helloWorld($name, $age) {
    ....
}

function showName($name) {
    ....
}

function showAge($age) {
    ....
}

function showPost($f, $message) {
   print_r($f);
   echo $message;
}

my libs are found in github with xjx as the project name
</pre>

Comments

0

let say we have couple of classes

class Request 
{
    private $req;

    public function __construct($req)
    {
        $this->req = $req;
    }

    public function __call($name, $arg)
    {
        return \call_user_func_array(array($this->req,$name), $arg);
    }
}

class Get 
{
    public function load($url)
    {
        // fire an http request
    }
}

class Post 
{
    public function load($url)
    {
        // fire an http request
    }

    public function attachHeader($header=[])
    {
        // attach an header to the request
    }
}

$request_1 = new Request(new Get());
$request_1->load($url);

$request_2 = new Request(new Post());
$request_2->attachHeader($header_data);
$request_2->load($url);

here you can see we can call the attachHeader() method by using of call_user_func_array() without any problem.

i hope it will help

Comments

0

I find it useful when working with variadic functions.

// a variadic function
function implode_this_array( $label, ...$items ) {
    echo $label . implode( '; ', $items );
}

// another variadic function
function some_other_function_elsewhere( ...$args ) {

    // do something here
    // ...
    // do something else here
    // ...

    call_user_func_array( 'implode_this_array', $args );

    // or the equivalent's PHP 7.4+ with the spread operator:
    // call_user_func_array( 'implode_this_array', [ ...$args ] );
}

some_other_function_elsewhere( 'I got this = ', 'foo', 'bar' );

Will output:

I got this = foo; bar

Now that I read this, perhaps it doesn't excel in readability. But it has its use sometimes.

edit: sorry, maybe a bit of a duplicate of another answer.

4 Comments

Especially with variadic functions you don't need it all, making it just 'implode_this_array'( ...$args );
@YourCommonSense Maybe an unfortunate written example at that moment. What I meant to show is that call_user_func_array might come in handy when you have the parameters to pass on ready as an array, and that's a case when you're inside a variadic function.
neither call_user_func_array nor call_user_func might come in handy in modern PHP at all. They are absoleted. When you need to call a function, variadic or not, you just call that function, itself.
It depends on what script are you working on and which PHP version you're bound to, one might not always have the luxury to work on a full modern PHP project. If the function receiving the parameters is not variadic for some reason, I find call_user_func_array useful, that may have been shown better in my example but I missed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.