If your function is meant to accept a variable number of
arguments, the snippets just described are sometimes suboptimal
solutions. You have to create a line calling
zend_get_parameters_ex() for every possible
number of arguments, which is often unsatisfying.
For this case, you can use the
function zend_get_parameters_array_ex(), which accepts the
number of parameters to retrieve and an array in which to store them:
zval **parameter_array[4];
/* get the number of arguments */
argument_count = ZEND_NUM_ARGS();
/* see if it satisfies our minimal request (2 arguments) */
/* and our maximal acceptance (4 arguments) */
if(argument_count < 2 || argument_count > 5)
WRONG_PARAM_COUNT;
/* argument count is correct, now retrieve arguments */
if(zend_get_parameters_array_ex(argument_count, parameter_array) != SUCCESS)
WRONG_PARAM_COUNT; |
First, the number of arguments is checked to make sure that it's in the accepted range. After that,
zend_get_parameters_array_ex() is used to
fill
parameter_array with valid pointers to the argument
values.
A very clever implementation of this can be found in the code
handling PHP's fsockopen() located in
ext/standard/fsock.c, as shown in
Example 52-1. Don't worry if you don't know all the functions used in this
source yet; we'll get to them shortly.
Example 52-1. PHP's implementation of variable arguments in fsockopen(). pval **args[5];
int *sock=emalloc(sizeof(int));
int *sockp;
int arg_count=ARG_COUNT(ht);
int socketd = -1;
unsigned char udp = 0;
struct timeval timeout = { 60, 0 };
unsigned short portno;
unsigned long conv;
char *key = NULL;
FLS_FETCH();
if (arg_count > 5 || arg_count < 2 || zend_get_parameters_array_ex(arg_count,args)==FAILURE) {
CLOSE_SOCK(1);
WRONG_PARAM_COUNT;
}
switch(arg_count) {
case 5:
convert_to_double_ex(args[4]);
conv = (unsigned long) (Z_DVAL_P(args[4]) * 1000000.0);
timeout.tv_sec = conv / 1000000;
timeout.tv_usec = conv % 1000000;
/* fall-through */
case 4:
if (!PZVAL_IS_REF(*args[3])) {
php_error(E_WARNING,"error string argument to fsockopen not passed by reference");
}
pval_copy_constructor(*args[3]);
ZVAL_EMPTY_STRING(*args[3]);
/* fall-through */
case 3:
if (!PZVAL_IS_REF(*args[2])) {
php_error(E_WARNING,"error argument to fsockopen not passed by reference");
return;
}
ZVAL_LONG(*args[2], 0);
break;
}
convert_to_string_ex(args[0]);
convert_to_long_ex(args[1]);
portno = (unsigned short) Z_LVAL_P(args[1]);
key = emalloc(Z_STRLEN_P(args[0]) + 10); |
|
fsockopen() accepts two, three, four, or five
parameters. After the obligatory variable declarations, the
function checks for the correct range of arguments. Then it uses a
fall-through mechanism in a switch() statement
to deal with all arguments. The switch()
statement starts with the maximum number of arguments being passed
(five). After that, it automatically processes the case of four
arguments being passed, then three, by omitting the otherwise
obligatory break keyword in all stages. After
having processed the last case, it exits the
switch() statement and does the minimal
argument processing needed if the function is invoked with only
two arguments.
This multiple-stage type of processing, similar to a stairway, allows
convenient processing of a variable number of arguments.