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:
s -
string (with possible null bytes) and its length
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*
| -
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.