Annotation of embedaddon/php/README.PARAMETER_PARSING_API, revision 1.1.1.3

1.1       misho       1: New parameter parsing functions
                      2: ===============================
                      3: 
                      4: It should be easier to parse input parameters to an extension function.
                      5: Hence, borrowing from Python's example, there are now a set of functions
                      6: that given the string of type specifiers, can parse the input parameters
                      7: and store the results in the user specified variables. This avoids most
                      8: of the IS_* checks and convert_to_* conversions. The functions also
                      9: check for the appropriate number of parameters, and try to output
                     10: meaningful error messages.
                     11: 
                     12: 
                     13: Prototypes
                     14: ----------
                     15: /* Implemented. */
                     16: int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...);
                     17: int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...);
                     18: 
                     19: The zend_parse_parameters() function takes the number of parameters
                     20: passed to the extension function, the type specifier string, and the
                     21: list of pointers to variables to store the results in. The _ex() version
                     22: also takes 'flags' argument -- current only ZEND_PARSE_PARAMS_QUIET can
                     23: be used as 'flags' to specify that the function should operate quietly
                     24: and not output any error messages.
                     25: 
                     26: Both functions return SUCCESS or FAILURE depending on the result.
                     27: 
                     28: The auto-conversions are performed as necessary. Arrays, objects, and
                     29: resources cannot be auto-converted.
                     30: 
                     31: 
                     32: Type specifiers
                     33: ---------------
                     34:  The following list shows the type specifier, its meaning and the parameter 
1.1.1.3 ! misho      35:  types that need to be passed by address. All passed parameters are set
1.1       misho      36:  if the PHP parameter is non optional and untouched if optional and the 
                     37:  parameter is not present. The only exception is O where the zend_class_entry*
                     38:  has to be provided on input and is used to verify the PHP parameter is an 
                     39:  instance of that class.
                     40: 
                     41:  a  - array (zval*)
                     42:  A  - array or object (zval *)
                     43:  b  - boolean (zend_bool)
                     44:  C  - class (zend_class_entry*)
                     45:  d  - double (double)
                     46:  f  - function or array containing php method call info (returned as 
                     47:       zend_fcall_info and zend_fcall_info_cache)
                     48:  h  - array (returned as HashTable*)
                     49:  H  - array or HASH_OF(object) (returned as HashTable*)
                     50:  l  - long (long)
                     51:  L  - long, limits out-of-range numbers to LONG_MAX/LONG_MIN (long)
                     52:  o  - object of any type (zval*)
                     53:  O  - object of specific type given by class entry (zval*, zend_class_entry)
1.1.1.2   misho      54:  p  - valid path (string without null bytes in the middle) and its length (char*, int)
1.1       misho      55:  r  - resource (zval*)
                     56:  s  - string (with possible null bytes) and its length (char*, int)
                     57:  z  - the actual zval (zval*)
                     58:  Z  - the actual zval (zval**)
                     59:  *  - variable arguments list (0 or more)
                     60:  +  - variable arguments list (1 or more)
                     61: 
                     62:  The following characters also have a meaning in the specifier string:
                     63:     | - indicates that the remaining parameters are optional, they
                     64:         should be initialized to default values by the extension since they
                     65:         will not be touched by the parsing function if they are not
                     66:         passed to it.
                     67:     / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
                     68:     ! - the parameter it follows can be of specified type or NULL (applies
                     69:                to all specifiers except for 'b', 'l', and 'd'). If NULL is passed, the
                     70:                results pointer is set to NULL as well.
                     71: 
                     72: 
                     73: Note on 64bit compatibility
                     74: ---------------------------
                     75: Please do not forget that int and long are two different things on 64bit 
                     76: OSes (int is 4 bytes and long is 8 bytes), so make sure you pass longs to "l" 
                     77: and ints to strings length (i.e. for "s" you need to pass char * and int), 
                     78: not the other way round!
                     79: Remember: "l" is the only case when you need to pass long (and that's why 
                     80: it's "l", not "i" btw).
                     81: 
                     82: Both mistakes cause memory corruptions and segfaults on 64bit OSes:
                     83: 1)
                     84:   char *str;
                     85:   long str_len; /* XXX THIS IS WRONG!! Use int instead. */
                     86:   zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len)
                     87: 
                     88: 2)
                     89:   int num; /* XXX THIS IS WRONG!! Use long instead. */
                     90:   zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &num)
                     91: 
                     92: If you're in doubt, use check_parameters.php script to the parameters 
                     93: and their types (it can be found in ./scripts/dev/ directory of PHP sources):
                     94: 
                     95: # php ./scripts/dev/check_parameters.php /path/to/your/sources/
                     96: 
                     97: 
                     98: Examples
                     99: --------
                    100: /* Gets a long, a string and its length, and a zval */
                    101: long l;
                    102: char *s;
                    103: int s_len;
                    104: zval *param;
                    105: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz",
                    106:                           &l, &s, &s_len, &param) == FAILURE) {
                    107:     return;
                    108: }
                    109: 
                    110: 
                    111: /* Gets an object of class specified by my_ce, and an optional double. */
                    112: zval *obj;
                    113: double d = 0.5;
                    114: zend_class_entry *my_ce;
                    115: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d",
                    116:                           &obj, my_ce, &d) == FAILURE) {
                    117:     return;
                    118: }
                    119: 
                    120: 
                    121: /* Gets an object or null, and an array.
                    122:    If null is passed for object, obj will be set to NULL. */
                    123: zval *obj;
                    124: zval *arr;
                    125: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a",
                    126:                           &obj, &arr) == FAILURE) {
                    127:     return;
                    128: }
                    129: 
                    130: 
                    131: /* Gets a separated array which can also be null. */
                    132: zval *arr;
                    133: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!",
                    134:                           &arr) == FAILURE) {
                    135:     return;
                    136: }
                    137: 
                    138: /* Get either a set of 3 longs or a string. */
                    139: long l1, l2, l3;
                    140: char *s;
                    141: /* 
                    142:  * The function expects a pointer to a integer in this case, not a long
                    143:  * or any other type.  If you specify a type which is larger
                    144:  * than a 'int', the upper bits might not be initialized
                    145:  * properly, leading to random crashes on platforms like
                    146:  * Tru64 or Linux/Alpha.
                    147:  */
                    148: int length;
                    149: 
                    150: if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
                    151:                              "lll", &l1, &l2, &l3) == SUCCESS) {
                    152:     /* manipulate longs */
                    153: } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
                    154:                                     "s", &s, &length) == SUCCESS) {
                    155:     /* manipulate string */
                    156: } else {
                    157:     /* output error */
                    158: 
                    159:     return;
                    160: }
                    161: 
                    162: 
                    163: /* Function that accepts only varargs (0 or more) */
                    164: 
                    165: int i, num_varargs;
                    166: zval ***varargs = NULL;
                    167: 
                    168: 
                    169: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &varargs, &num_varargs) == FAILURE) {
                    170:     return;
                    171: }
                    172: 
                    173: for (i = 0; i < num_varargs; i++) {
                    174:     /* do something with varargs[i] */
                    175: }
                    176: 
                    177: if (varargs) {
                    178:     efree(varargs);
                    179: }
                    180: 
                    181: 
                    182: /* Function that accepts a string, followed by varargs (1 or more) */
                    183: 
                    184: char *str;
                    185: int str_len;
                    186: int i, num_varargs;
                    187: zval ***varargs = NULL;
                    188: 
                    189: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) {
                    190:     return;
                    191: }
                    192: 
                    193: for (i = 0; i < num_varargs; i++) {
                    194:     /* do something with varargs[i] */
                    195: }
                    196: 
                    197: if (varargs) {
                    198:     efree(varargs);
                    199: }
                    200: 
                    201: 
                    202: /* Function that takes an array, followed by varargs, and ending with a long */
                    203: long num;
                    204: zval *array;
                    205: int i, num_varargs;
                    206: zval ***varargs = NULL;
                    207: 
                    208: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) {
                    209:     return;
                    210: }
                    211: 
                    212: for (i = 0; i < num_varargs; i++) {
                    213:     /* do something with varargs[i] */
                    214: }
                    215: 
                    216: if (varargs) {
                    217:     efree(varargs);
                    218: }
                    219: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>