New parameter parsing API: This chapter documents the new Zend parameter parsing API introduced by Andrei Zmievski. It was introduced in the development stage between PHP 4.0.6 and 4.1.0 .
Parsing parameters is a very common operation and it may
get a bit tedious. It would also be nice to have standardized
error checking and error messages. Since PHP 4.1.0, there is
a way to do just that by using the new parameter parsing API.
It greatly simplifies the process of receiving parameteres,
but it has a drawback in that it can't be used for functions
that expect variable number of parameters. But since the vast
majority of functions do not fall into those categories, this
parsing API is recommended as the new standard way.
The prototype for parameter parsing function looks like
this:
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...); |
zend_parse_parameters() also
performs type conversions whenever possible, so that you
always receive the data in the format you asked for. Any type
of scalar can be converted to another one, but conversions
between complex types (arrays, objects, and resources) and
scalar types are not allowed.
If the parameters could be obtained successfully and
there were no errors during type conversion, the function
will return SUCCESS, otherwise it
will return FAILURE. The function
will output informative error messages, if the number of
received parameters does not match the requested number, or
if type conversion could not be performed.
Here are some sample error messages:
Warning - ini_get_all() requires at most 1 parameter, 2 given Warning - wddx_deserialize() expects parameter 1 to be string, array given |
Here is the full list of type specifiers:
l - long
d - double
s - string (with possible
null bytes) and its length
b - boolean
r - resource, stored in zval*
a - array, stored in zval*
o - object (of any class),
stored in zval*
O - object (of class
specified by class entry), stored in
zval*
z - the actual zval*
| - indicates that the
remaining parameters are optional. The storage variables
corresponding to these parameters should be initialized
to default values by the extension, since they will not
be touched by the parsing function if the parameters are
not passed.
/ - the parsing function
will call
SEPARATE_ZVAL_IF_NOT_REF() on the parameter it
follows, to provide a copy of the parameter, unless it's
a reference.
! - the parameter it
follows can be of specified type or
NULL (only applies to a, o, O, r, and z). If NULL value is passed by the user,
the storage pointer will be set to
NULL.
The best way to illustrate the usage of this function is
through examples:
/* Gets a long, a string and its length, and a zval. */ long l; char *s; int s_len; zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz", l, s, s_len, param) == FAILURE) { return; } /* Gets an object of class specified by my_ce, and an optional double. */ zval *obj; double d = 0.5; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d", obj, my_ce, d) == FAILURE) { return; } /* Gets an object or null, and an array. If null is passed for object, obj will be set to NULL. */ zval *obj; zval *arr; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!a", obj, arr) == FAILURE) { return; } /* Gets a separated array. */ zval *arr; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", arr) == FAILURE) { return; } /* Get only the first three parameters (useful for varargs functions). */ zval *z; zend_bool b; zval *r; if (zend_parse_parameters(3, "zbr!", z, b, r) == FAILURE) { return; } |
Note that in the last example we pass 3 for the number
of received parameters, instead of
ZEND_NUM_ARGS(). What this lets us do is receive the
least number of parameters if our function expects a variable
number of them. Of course, if you want to operate on the rest
of the parameters, you will have to use
zend_get_parameters_array_ex() to obtain them.
The parsing function has an extended version that allows
for an additional flags argument that controls its
actions.
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...); |
The only flag you can pass currently is ZEND_PARSE_PARAMS_QUIET, which instructs the
function to not output any error messages during its
operation. This is useful for functions that expect several
sets of completely different arguments, but you will have to
output your own error messages.
For example, here is how you would get either a set of
three longs or a string:
long l1, l2, l3; char *s; if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "lll", l1, l2, l3) == SUCCESS) { /* manipulate longs */ } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s", s, s_len) == SUCCESS) { /* manipulate string */ } else { php_error(E_WARNING, "%s() takes either three long values or a string as argument", get_active_function_name(TSRMLS_C)); return; } |
With all the abovementioned ways of receiving function
parameters you should have a good handle on this process. For
even more example, look through the source code for
extensions that are shipped with PHP - they illustrate every
conceivable situation.