File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / README.PARAMETER_PARSING_API
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:31:37 2013 UTC (11 years, 5 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_29, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    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 parameters 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:  p  - valid path (string without null bytes in the middle) and its length (char*, int)
   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>