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
?
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With