tags:

views:

449

answers:

6

How do I write a function that can accept unlimited number of parameters?

What am trying to do is create a function within a class that wraps the following:

$stmt->bind_param('sssd', $code, $language, $official, $percent);
+11  A: 

Have you taken a look at func_get_args, func_get_arg and func_num_args

So for example:

function foo(){
    if ( func_num_args() > 0 ){
        var_dump(func_get_args());
    }
}

or:

function bind_param(){
    if ( func_num_args() <= 1 ){
        return false; //not enough args
    }
    $format = func_get_arg(0)
    $args = array_slice(func_get_args(), 1)

    //etc
}

EDIT
Regarding Ewan Todds comment:
I don't have any knowlege of the base API you are creating the wrapper for, but another alternative may be to do something with chaining functions so your resulting interface looks something like:

$var->bind()->bindString($code)
            ->bindString($language)
            ->bindString($official)
            ->bindDecimal($percent);

Which I would prefer over the use of func_get_args as the code is probably more readable and more importantly less likely to cause errors due to the the lack of a format variable.

Yacoby
I use func_get_args from time to time. It suffers from making it difficult see at a glance what the method's inputs are. Plus, it introduces a block of butt ugly syntax into your code. I would recommend this approach only as a last resort. Prefer the Parameter Object refactoring.
Ewan Todd
I agree with you that it is a bad way of doing variable arguments. I have added an alternative idea to my answer
Yacoby
I like the "chaining functions" proposal better than func_get_args. I know this design as a FLUENT interface. It is accomplished by having bindString(), bindDecimal() etc. do "return $this;" as their last line. The FLUENT interface is a great option for cetain types of factory.
Ewan Todd
+1  A: 

There is a function called func_get_args() which is an array of all arguments passed to the function.

Example from PHP.net

function foo()
{
    $numargs = func_num_args();
    echo "Number of arguments: $numargs<br />\n";
    if ($numargs >= 2) {
        echo "Second argument is: " . func_get_arg(1) . "<br />\n";
    }
    $arg_list = func_get_args();
    for ($i = 0; $i < $numargs; $i++) {
        echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
    }
}

foo(1, 2, 3);

The above example will output:

Number of arguments: 3
Second argument is: 2
Argument 0 is: 1
Argument 1 is: 2
Argument 2 is: 3

Ólafur Waage
+4  A: 

Use func_get_args():

function my_func() {
  $args = func_get_args();
  foreach ($args as $arg) {
    echo "Arg: $arg\n";
  }
}
cletus
+2  A: 

The above suggests are all good, but I don't think they will be suitable for your situation.

$stmt->bind_param('sssd', $code, $language, $official, $percent);

If you want to wrap this function, you will need to pass references to the original argument variables to the bind_param function. I don't think func_get_args() gives you this, it gives you values instead. Thus it won't be possible to use these to pass to the parent function. I battled with a similar issue when trying to extend mysqli_stmt and never came to satisfactory solution.

This is not really an answer to your question I'm afraid, just a warning that other arguments may not work in your particular application of arbitrary number of arguments.

Rob Tuley
Indeed. Last time I checked (1+ year ago) there was no way to wrap/extend `bind_param()` because `func_get_args()` won't return references.
Josh Davis
+3  A: 

At 5 parameters, this design is starting to exhibit the AntiPattern "Too Many Parameters". This suggests the refactoring called Parameter Object, an object or structure with data members representing the arguments to be passed in. However, avoid making it a Magic Container.

See also Introduce Parameter Object refactoring at refactoring.com.

Ewan Todd
A: 

Thanks alot guys. I'm sorry it wasn't clear it was a mysqli function. I made the assumption everyone here would know.

Ageis