====== PHP RFC: Fast Parameter Parsing API ====== * Version: 0.9 * Date: 2014-05-23 * Author: Dmitry Stogov , Bob Weinand * Status: Implemented (PHP 7.0) * First Published at: http://wiki.php.net/rfc/fast_zpp ===== Introduction ===== PHP internal functions use zend_parse_parameters() API to receive values of actual parameters into C variables. This function uses scanf() like approach for parameter definition. The number and types of required data defined by a string that contains a list of specifiers ("s" - for string, "l" for long, etc). Unfortunately, this string has to be parsed each time when php calls this function, and this makes significant performance overhead. For example zend_parse_parameters() takes ~6% of CPU time in serving wordpress home page. For some really simple function like is_string() or ord() the overhead of zend_parse_parameters() may be about 90%. ===== Proposal ===== We propose an additional fast API for parameter parsing, that should be used for the most useful functions. The API is based on C macros that lead to inlining of optimized code directly into the body of internal function. **We don't propose to remove the existing API, and would suggest to use fast API only for most often used functions to get performance boost.** I'll explain API on the following example: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|zb", &input, &offset, &z_length, &preserve_keys) == FAILURE) { return; } ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_ARRAY(input) Z_PARAM_LONG(offset) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(z_length) Z_PARAM_BOOL(preserve_keys) ZEND_PARSE_PARAMETERS_END(); The first code fragment is just taken from PHP_FUNCTION(array_slice), the second is its replacement using new API. The code is actually self explainable. ZEND_PARSE_PARAMETERS_START() takes two arguments minimal and maximal parameters count. Z_PARAM_ARRAY() - takes the next argument as array, Z_PARAM_LONG - as long, Z_PARAM_OPTIONAL - tells that the remaining arguments are optional. The new API covers all possibilities of the existing API. The following table shows the correspondence between old specifiers and new macros. ^ specifier ^ Fast ZPP API macro ^ args ^ | ''|'' | Z_PARAM_OPTIONAL || | a | Z_PARAM_ARRAY(dest) | dest - zval* | | A | Z_PARAM_ARRAY_OR_OBJECT(dest) | dest - zval* | | b | Z_PARAM_BOOL(dest) | dest - zend_bool | | C | Z_PARAM_CLASS(dest) | dest - zend_class_entry* | | d | Z_PARAM_DOUBLE(dest) | dest - double | | f | Z_PARAM_FUNC(fci, fcc) | fci - zend_fcall_info, fcc - zend_fcall_info_cache | | h | Z_PARAM_ARRAY_HT(dest) | dest - HashTable* | | H | Z_PARAM_ARRAY_OR_OBJECT_HT(dest) | dest - HashTable* | | l | Z_PARAM_LONG(dest) | dest - long | | L | Z_PARAM_STRICT_LONG(dest) | dest - long | | o | Z_PARAM_OBJECT(dest) | dest - zval* | | O | Z_PARAM_OBJECT_OF_CLASS(dest, ce) | dest - zval* | | p | Z_PARAM_PATH(dest, dest_len) | dest - char*, dest_len - int | | P | Z_PARAM_PATH_STR(dest) | dest - zend_string* | | r | Z_PARAM_RESOURCE(dest) | dest - zval* | | s | Z_PARAM_STRING(dest, dest_len) | dest - char*, dest_len - int | | S | Z_PARAM_STR(dest) | dest - zend_string* | | z | Z_PARAM_ZVAL(dest) | dest - zval* | | | Z_PARAM_ZVAL_DEREF(dest) | dest - zval* | | + | Z_PARAM_VARIADIC('+', dest, num) | dest - zval*, num int | | * | Z_PARAM_VARIADIC('*', dest, num) | dest - zval*, num int | The effect of **!** and reference modifiers may be achieved using extended version of the same macros e.g. Z_PARAM_ZVAL_EX(dest, check_null, separate). ==== Performance Evaluation ==== The following numbers collected for 100 and 1000 requests to wordpress home page. ^ ^ # of CPU instructions ^ time [sec] ^ | phpng | 5,132,181,672| 18.90| | phpng + fast_zpp | 4,901,907,204| 18.40| So the proposal provides 4.5% improvement in terms of CPU instructions and 2.5% in terms of time. The effect of code size increase is negligible. Just ~20KB for ~70 function (that's below 0.1%) ===== Backward Incompatible Changes ===== The new API provides exactly the same behavior. Also, we don't propose to remove the old API. So there must not be any compatibility problems. ===== Proposed PHP Version(s) ===== This proposal is targeted to php-7 ===== Vote ===== State whether this project requires 50%+1 majority (see [[voting]]). The vote is a straight Yes/No vote. * Yes * No The vote concluded on January 27th. ===== Patches and Tests ===== * Original Proposal: https://gist.github.com/dstogov/1131691470a4c37540a6 The patch is already included into PHP-7 and wrapped with ifdef/ifndef FAST_ZPP.