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, ...); |
The first argument to this function is supposed to be the number
of actual parameters passed to your function, so
ZEND_NUM_ARGS() can be used for that. The
second parameter should always be
TSRMLS_CC
macro. The third argument is a string that specifies the number
and types of arguments your function is expecting, similar to how
printf format string specifies the number and format of the output
values it should operate on. And finally the rest of the arguments
are pointers to variables which should receive the values from the
parameters.
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 |
Of course each error message is accompanied by the filename and
line number on which it occurs.
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*
The following characters also have a meaning in the specifier
string:
| - 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, ¶m) == 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.