Annotation of embedaddon/php/README.PARAMETER_PARSING_API, revision 1.1.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>