Reputation: 300
When trying to call a function in a child class with an arbitrary set of parameters, I'm having the following problem:
class Base{
function callDerived($method,$params){
call_user_func_array(array($this,$method),$params);
}
}
class Derived extends Base{
function test($foo,$bar){
print "foo=$foo, bar=$bar\n";
}
}
$d = new Derived();
$d->callDerived('test',array('bar'=>'2','foo'=>1));
Outputs:
foo=2, bar=1
Which... is not exactly what I wanted - is there a way to achieve this beyond re-composing the array with the index order of func_get_args? And yes, of course, I could simply pass the whole array and deal with it in the function... but that's not what I want to do.
Thanks
Upvotes: 16
Views: 27153
Reputation: 5851
UPDATE: PHP 8 Now supports named parameters. And it works with call_user_func_array
if you pass an associative array. So you can simply do this:
<?php
function myFunc($foo, $bar) {
echo "foo=$foo, bar=$bar\n";
}
call_user_func_array('myFunc', ['bar' => 2, 'foo' => 1]);
// Outputs: foo=1, bar=2
In your code, you'll be happy to know that you don't have to change a thing. Just upgrade to PHP 8 and it'll work as you expected
Upvotes: 5
Reputation: 183
For those who still might stumble on the question (like I did), here is my approach:
since PHP 5.6 you can use ... as mentioned here:
In this case you could use something like this:
class Base{
function callDerived($method,...$params){
call_user_func_array(array($this,$method),$params);
}
}
class Derived extends Base{
function test(...$params){
foreach ($params as $arr) {
extract($arr);
}
print "foo=$foo, bar=$bar\n";
}
}
$d = new Derived();
$d->callDerived('test',array('bar'=>'2'),array('foo'=>1));
//print: foo=1, bar=2
Upvotes: 1
Reputation: 139
I use a bitmask instead of boolean parameters:
// Ingredients
define ('TOMATO', 0b0000001);
define ('CHEESE', 0b0000010);
define ('OREGANO', 0b0000100);
define ('MUSHROOMS', 0b0001000);
define ('SALAMI', 0b0010000);
define ('PEPERONI', 0b0100000);
define ('ONIONS', 0b1000000);
function pizza ($ingredients) {
$serving = 'Pizza with';
$serving .= ($ingredients&TOMATO)?' Tomato':'';
$serving .= ($ingredients&CHEESE)?' Cheese':'';
$serving .= ($ingredients&OREGANO)?' Oregano':'';
$serving .= ($ingredients&MUSHROOMS)?' Mushrooms':'';
$serving .= ($ingredients&SALAMI)?' Salami':'';
$serving .= ($ingredients&ONIONS)?' Onions':'';
return trim($serving)."\n" ;
}
// Now order your pizzas!
echo pizza(TOMATO | CHEESE | SALAMI);
echo pizza(ONIONS | TOMATO | MUSHROOMS | CHEESE); // "Params" are not positional
Upvotes: 3
Reputation: 1084
You can simply pass an array and extract:
function add($arr){
extract($arr, EXTR_REFS);
return $one+$two;
}
$one = 1;
$two = 2;
echo add(compact('one', 'two')); // 3
This will extract as references, so there is close to no overhead.
Upvotes: 3
Reputation: 3334
Good news, I had the same concern (I was looking for named arguments in PHP, like Python does), and found this useful tool : https://github.com/PHP-DI/Invoker
This uses the reflection API to feed a callable with some arguments from an array and also use optional arguments defaults for other parameters that are not defined in the array.
$invoker = new Invoker\Invoker;
$result = $invoker->call(array($object, 'method'), array(
"strName" => "Lorem",
"strValue" => "ipsum",
"readOnly" => true,
"size" => 55,
));
Have fun
Upvotes: 5
Reputation: 175
The stock PHP class ReflectionMethod is your friend.
Example:
class MyClass {
function myFunc($param1, $param2, $param3='myDefault') {
print "test";
}
}
$refm = new ReflectionMethod('MyClass', 'myFunc');
foreach ($refm->getParameters() as $p)
print "$p\n";
And the result:
Parameter #0 [ <required> $param1 ]
Parameter #1 [ <required> $param2 ]
Parameter #2 [ <optional> $param3 = 'myDefault' ]
At this point you know the names of the parameters of the target function. With this information you can modify your method 'callDerived', and you can re-order the array to call_user_func_array according to the parameter names.
Upvotes: 8
Reputation: 158
There is a way to do it and is using arrays (the most easy way):
class Test{
public $a = false;
private $b = false;
public $c = false;
public $d = false;
public $e = false;
public function _factory(){
$args = func_get_args();
$args = $args[0];
$this->a = array_key_exists("a",$args) ? $args["a"] : 0;
$this->b = array_key_exists("b",$args) ? $args["b"] : 0;
$this->c = array_key_exists("c",$args) ? $args["c"] : 0;
$this->d = array_key_exists("d",$args) ? $args["d"] : 0;
$this->e = array_key_exists("e",$args) ? $args["e"] : 0;
}
public function show(){
var_dump($this);
}
}
$test = new Test();
$args["c"]=999;
$test->_factory($args);
$test->show();
a full explanation can be found in my blog: http://www.tbogard.com/2013/03/07/passing-named-arguments-to-a-function-in-php/
Upvotes: -1
Reputation: 522145
No. PHP does not support named parameters. Only the order of parameters is taken into account. You could probably take the code itself apart using the ReflectionClass to inspect the function parameter names, but in the end you'd need to use this to reorder the array anyway.
Upvotes: 24