Annotation of embedaddon/php/README.PARAMETER_PARSING_API, revision 1.1
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
! 35: types that need to be passed by address. All passed paramaters are set
! 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)
! 54: r - resource (zval*)
! 55: s - string (with possible null bytes) and its length (char*, int)
! 56: z - the actual zval (zval*)
! 57: Z - the actual zval (zval**)
! 58: * - variable arguments list (0 or more)
! 59: + - variable arguments list (1 or more)
! 60:
! 61: The following characters also have a meaning in the specifier string:
! 62: | - indicates that the remaining parameters are optional, they
! 63: should be initialized to default values by the extension since they
! 64: will not be touched by the parsing function if they are not
! 65: passed to it.
! 66: / - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
! 67: ! - the parameter it follows can be of specified type or NULL (applies
! 68: to all specifiers except for 'b', 'l', and 'd'). If NULL is passed, the
! 69: results pointer is set to NULL as well.
! 70:
! 71:
! 72: Note on 64bit compatibility
! 73: ---------------------------
! 74: Please do not forget that int and long are two different things on 64bit
! 75: OSes (int is 4 bytes and long is 8 bytes), so make sure you pass longs to "l"
! 76: and ints to strings length (i.e. for "s" you need to pass char * and int),
! 77: not the other way round!
! 78: Remember: "l" is the only case when you need to pass long (and that's why
! 79: it's "l", not "i" btw).
! 80:
! 81: Both mistakes cause memory corruptions and segfaults on 64bit OSes:
! 82: 1)
! 83: char *str;
! 84: long str_len; /* XXX THIS IS WRONG!! Use int instead. */
! 85: zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len)
! 86:
! 87: 2)
! 88: int num; /* XXX THIS IS WRONG!! Use long instead. */
! 89: zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &num)
! 90:
! 91: If you're in doubt, use check_parameters.php script to the parameters
! 92: and their types (it can be found in ./scripts/dev/ directory of PHP sources):
! 93:
! 94: # php ./scripts/dev/check_parameters.php /path/to/your/sources/
! 95:
! 96:
! 97: Examples
! 98: --------
! 99: /* Gets a long, a string and its length, and a zval */
! 100: long l;
! 101: char *s;
! 102: int s_len;
! 103: zval *param;
! 104: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz",
! 105: &l, &s, &s_len, ¶m) == FAILURE) {
! 106: return;
! 107: }
! 108:
! 109:
! 110: /* Gets an object of class specified by my_ce, and an optional double. */
! 111: zval *obj;
! 112: double d = 0.5;
! 113: zend_class_entry *my_ce;
! 114: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d",
! 115: &obj, my_ce, &d) == FAILURE) {
! 116: return;
! 117: }
! 118:
! 119:
! 120: /* Gets an object or null, and an array.
! 121: If null is passed for object, obj will be set to NULL. */
! 122: zval *obj;
! 123: zval *arr;
! 124: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a",
! 125: &obj, &arr) == FAILURE) {
! 126: return;
! 127: }
! 128:
! 129:
! 130: /* Gets a separated array which can also be null. */
! 131: zval *arr;
! 132: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/!",
! 133: &arr) == FAILURE) {
! 134: return;
! 135: }
! 136:
! 137: /* Get either a set of 3 longs or a string. */
! 138: long l1, l2, l3;
! 139: char *s;
! 140: /*
! 141: * The function expects a pointer to a integer in this case, not a long
! 142: * or any other type. If you specify a type which is larger
! 143: * than a 'int', the upper bits might not be initialized
! 144: * properly, leading to random crashes on platforms like
! 145: * Tru64 or Linux/Alpha.
! 146: */
! 147: int length;
! 148:
! 149: if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
! 150: "lll", &l1, &l2, &l3) == SUCCESS) {
! 151: /* manipulate longs */
! 152: } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
! 153: "s", &s, &length) == SUCCESS) {
! 154: /* manipulate string */
! 155: } else {
! 156: /* output error */
! 157:
! 158: return;
! 159: }
! 160:
! 161:
! 162: /* Function that accepts only varargs (0 or more) */
! 163:
! 164: int i, num_varargs;
! 165: zval ***varargs = NULL;
! 166:
! 167:
! 168: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &varargs, &num_varargs) == FAILURE) {
! 169: return;
! 170: }
! 171:
! 172: for (i = 0; i < num_varargs; i++) {
! 173: /* do something with varargs[i] */
! 174: }
! 175:
! 176: if (varargs) {
! 177: efree(varargs);
! 178: }
! 179:
! 180:
! 181: /* Function that accepts a string, followed by varargs (1 or more) */
! 182:
! 183: char *str;
! 184: int str_len;
! 185: int i, num_varargs;
! 186: zval ***varargs = NULL;
! 187:
! 188: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s+", &str, &str_len, &varargs, &num_varargs) == FAILURE) {
! 189: return;
! 190: }
! 191:
! 192: for (i = 0; i < num_varargs; i++) {
! 193: /* do something with varargs[i] */
! 194: }
! 195:
! 196: if (varargs) {
! 197: efree(varargs);
! 198: }
! 199:
! 200:
! 201: /* Function that takes an array, followed by varargs, and ending with a long */
! 202: long num;
! 203: zval *array;
! 204: int i, num_varargs;
! 205: zval ***varargs = NULL;
! 206:
! 207: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a*l", &array, &varargs, &num_varargs, &num) == FAILURE) {
! 208: return;
! 209: }
! 210:
! 211: for (i = 0; i < num_varargs; i++) {
! 212: /* do something with varargs[i] */
! 213: }
! 214:
! 215: if (varargs) {
! 216: efree(varargs);
! 217: }
! 218:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>