summaryrefslogtreecommitdiff
path: root/docs/parameter-parsing-api.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/parameter-parsing-api.md')
-rw-r--r--docs/parameter-parsing-api.md245
1 files changed, 245 insertions, 0 deletions
diff --git a/docs/parameter-parsing-api.md b/docs/parameter-parsing-api.md
new file mode 100644
index 0000000000..f65c19a723
--- /dev/null
+++ b/docs/parameter-parsing-api.md
@@ -0,0 +1,245 @@
+Fast Parameter Parsing API
+==========================
+
+In PHP 7, a "Fast Parameter Parsing API" was introduced. See
+
+ https://wiki.php.net/rfc/fast_zpp
+
+This API uses inlining to improve applications performance compared
+with the zend_parse_parameters() function described below.
+
+
+Parameter parsing functions
+===========================
+
+Borrowing from Python's example, there is 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
+using 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, &param) == 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;
+}