123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- New parameter parsing functions
- ===============================
- It should be easier to parse input parameters to an extension function.
- Hence, borrowing from Python's example, there are now a set of functions
- that given the string of type specifiers, can parse the input parameters
- and store the results in the user specified variables. This avoids most
- of the IS_* checks and convert_to_* conversions. The functions also
- check for the appropriate number of parameters, and try to output
- meaningful error messages.
- Prototypes
- ----------
- /* Implemented. */
- int zend_parse_parameters(int num_args, char *type_spec, ...);
- int zend_parse_parameters_ex(int flags, int num_args, char *type_spec, ...);
- The zend_parse_parameters() function takes the number of parameters
- passed to the extension function, the type specifier string, and the
- list of pointers to variables to store the results in. The _ex() version
- also takes 'flags' argument -- current only ZEND_PARSE_PARAMS_QUIET can
- be used as 'flags' to specify that the function should operate quietly
- and not output any error messages.
- Both functions return SUCCESS or FAILURE depending on the result.
- The auto-conversions are performed as necessary. Arrays, objects, and
- resources cannot be auto-converted.
- PHP 5.3 includes a new function (actually implemented as macro):
- int zend_parse_parameters_none();
- This returns SUCCESS if no argument has been passed to the function,
- FAILURE otherwise.
- PHP 5.5 includes a new function:
- int zend_parse_parameter(int flags, int arg_num, zval **arg, const char *spec, ...);
- This function behaves like zend_parse_parameters_ex() except that instead of
- reading the arguments from the stack, it receives a single zval to convert
- (passed with double indirection). The passed zval may be changed in place as
- part of the conversion process.
- See also https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter
- Type specifiers
- ---------------
- The following list shows the type specifier, its meaning and the parameter
- types that need to be passed by address. All passed parameters are set
- if the PHP parameter is non optional and untouched if optional and the
- parameter is not present. The only exception is O where the zend_class_entry*
- has to be provided on input and is used to verify the PHP parameter is an
- instance of that class.
- a - array (zval*)
- A - array or object (zval*)
- b - boolean (zend_bool)
- C - class (zend_class_entry*)
- d - double (double)
- f - function or array containing php method call info (returned as
- zend_fcall_info and zend_fcall_info_cache)
- h - array (returned as HashTable*)
- H - array or HASH_OF(object) (returned as HashTable*)
- l - long (zend_long)
- L - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (zend_long, ZEND_LONG_MAX/ZEND_LONG_MIN)
- o - object of any type (zval*)
- O - object of specific type given by class entry (zval*, zend_class_entry)
- p - valid path (string without null bytes in the middle) and its length (char*, size_t)
- P - valid path (string without null bytes in the middle) as zend_string (zend_string*)
- r - resource (zval*)
- s - string (with possible null bytes) and its length (char*, size_t)
- S - string (with possible null bytes) as zend_string (zend_string*)
- z - the actual zval (zval*)
- * - variable arguments list (0 or more)
- + - variable arguments list (1 or more)
- The following characters also have a meaning in the specifier string:
- | - indicates that the remaining parameters are optional, they
- should be initialized to default values by the extension since they
- will not be touched by the parsing function if they are not
- passed to it.
- / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
- ! - the parameter it follows can be of specified type or NULL. If NULL is
- passed and the output for such type is a pointer, then the output
- pointer is set to a native NULL pointer.
- For 'b', 'l' and 'd', an extra argument of type zend_bool* must be
- passed after the corresponding bool*, zend_long* or double* arguments,
- respectively. A non-zero value will be written to the zend_bool if a
- PHP NULL is passed.
- Note on 64bit compatibility
- ---------------------------
- Please note that since version 7 PHP uses zend_long as integer type and
- zend_string with size_t as length, so make sure you pass zend_longs to "l"
- and size_t to strings length (i.e. for "s" you need to pass char * and size_t),
- not the other way round!
- Both mistakes might cause memory corruptions and segfaults:
- 1)
- char *str;
- long str_len; /* XXX THIS IS WRONG!! Use size_t instead. */
- zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len)
- 2)
- int num; /* XXX THIS IS WRONG!! Use zend_long instead. */
- zend_parse_parameters(ZEND_NUM_ARGS(), "l", &num)
- If you're in doubt, use check_parameters.php script to the parameters
- and their types (it can be found in ./scripts/dev/ directory of PHP sources):
- # php ./scripts/dev/check_parameters.php /path/to/your/sources/
- Examples
- --------
- /* Gets a long, a string and its length, and a zval */
- zend_long l;
- char *s;
- size_t s_len;
- zval *param;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "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;
- zend_class_entry *my_ce;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "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(), "o!a",
- &obj, &arr) == FAILURE) {
- return;
- }
- /* Gets a separated array which can also be null. */
- zval *arr;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a/!",
- &arr) == FAILURE) {
- return;
- }
- /* Get either a set of 3 longs or a string. */
- zend_long l1, l2, l3;
- char *s;
- /*
- * The function expects a pointer to a size_t in this case, not a long
- * or any other type. If you specify a type which is larger
- * than a 'size_t', the upper bits might not be initialized
- * properly, leading to random crashes on platforms like
- * Tru64 or Linux/Alpha.
- */
- size_t length;
- if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "lll", &l1, &l2, &l3) == SUCCESS) {
- /* manipulate longs */
- } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
- "s", &s, &length) == SUCCESS) {
- /* manipulate string */
- } else {
- /* output error */
- return;
- }
- /* Function that accepts only varargs (0 or more) */
- int i, num_varargs;
- zval *varargs = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &varargs, &num_varargs) == FAILURE) {
- return;
- }
- for (i = 0; i < num_varargs; i++) {
- /* do something with varargs[i] */
- }
- if (varargs) {
- efree(varargs);
- }
- /* Function that accepts a string, followed by varargs (1 or more) */
- char *str;
- size_t str_len;
- int i, num_varargs;
- zval *varargs = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) {
- return;
- }
- for (i = 0; i < num_varargs; i++) {
- /* do something with varargs[i] */
- }
- /* Function that takes an array, followed by varargs, and ending with a long */
- zend_long num;
- zval *array;
- int i, num_varargs;
- zval *varargs = NULL;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) {
- return;
- }
- for (i = 0; i < num_varargs; i++) {
- /* do something with varargs[i] */
- }
- /* Function that doesn't accept any arguments */
- if (zend_parse_parameters_none() == FAILURE) {
- return;
- }
|