1. Internal API changes
========================
- a. Executor changes
-
- * extensions can't override zend_execute() any more, they should override
- zend_execute_ex() instead. The EG(current_execute_data) is already
- initialized in zend_execute_ex(), so for compatibility extensions
- may need to use EG(current_execute_data)->prev_execute_data instead.
- * removed EG(arg_types_stack), EX(fbc), EX(called_scope), EX(current_object)
- * added op_array->nested_calls. It's calculated at compile time.
- * added EX(call_slots). It is an array to store information about syntaticaly
- nested calls (e.g. foo(bar())). It's preallocated together with execute_data.
- * added EX(call) - pointer to a current calling function. Actually an
- element of EX(call_slots)
- * opcodes INIT_METHOD_CALL, ZEND_INIT_STATIC_METHOD_CALL,
- ZEND_INIT_FCALL_BY_NAME, ZEND_INIT_NS_FCALL_BY_NAME use result.num as
- an index in EX(call_slots)
- * opcode ZEND_NEW uses extended_vallue as an index in EX(call_slots)
- * opcoes ZEND_DO_FCALL and ZEND_DO_FCALL_BY_NAME use op2.num as
- an index in EX(call_slots)
- * added op_array->used_stack. It's calculated at compile time and the
- corresponding stack space is preallocated together with execute_data.
- ZEND_SEND* and ZEND_DO_FCALL* don't need to check for stack overflow
- anymore.
- * Removed execute_data->Ts field. The VM temporary variables always allocated
- immediately before execute_data structure. Now they are accessed by offset
- from the execute_data base pointer (instead of execute_data->Ts). Compiler
- stores new offsets in op_array->opcodes[*].op?.num. You can use macros
- EX_TMP_VAR() and EX_TMP_VAR_NUM() to access temp_variable by offset or
- number. You can convert number to offset using EX_TMP_VAR_NUM(0, num) or
- offset to number (EX_TMP_VAR_NUM(0,0)-EX_TMP_VAR(0,offset)).
- * Removed execute_data->CVs field. The VM compiled variables always allocated
- immediately after execute_data structure. Now they are accessed by offset
- from the execute_data base pointer (instead of execute_data->CVs). You can
- use macros EX_CV_NUM() to access compiled variables by number.
-
- b. Streams pooling API
-
-The streams pooling API has been removed. The following functions no longer
-exist:
-
-PHPAPI int php_stream_context_get_link(php_stream_context *context,
- const char *hostent, php_stream **stream);
-PHPAPI int php_stream_context_set_link(php_stream_context *context,
- const char *hostent, php_stream *stream);
-PHPAPI int php_stream_context_del_link(php_stream_context *context,
- php_stream *stream);
-
- c. Lowercasing and locales
-
-The lowercasing functions in zend_operators.c were split into those that do
-lowercasing according to locale rules and those that do ASCII lowercasing.
-ASCII:
-
- zend_str_tolower_copy
- zend_str_tolower_dup
- zend_str_tolower
- zend_binary_strcasecmp
- zend_binary_strncasecmp
-
-Locale-based:
- zend_binary_strncasecmp_l
- zend_binary_strcasecmp_l
- zend_binary_zval_strcasecmp
- zend_binary_zval_strncasecmp
- string_compare_function_ex
- string_case_compare_function
-
-Internal engine lowercasing will be using ASCII-only rules. User-facing functions,
-such as strcasecmp, will be using locale rules.
-
-Two new functions - zend_binary_strncasecmp_l and zend_binary_strcasecmp_l - added as
-locale-based counterparts to zend_binary_strcasecmp and zend_binary_strncasecmp.
-
- d. zend_qsort_r
-
-Added the function zend_qsort_r():
-
-typedef int (*compare_r_func_t)(const void *, const void * TSRMLS_DC, void *);
-void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare, void *arg TSRMLS_DC);
-
-The extra argument it has (relatively to zend_qsort()) is passed to the
-comparison function.
-
- e. get_current_key
-
-The signature of the get_current_key iteration handler has been changed to:
-
-void (*get_current_key)(zend_object_iterator *iter, zval *key TSRMLS_DC);
-
-The key should be written into the zval* using the ZVAL_* macros.
+ a. Addition of do_operation and compare object handlers
+
+ Two new object handlers have been added:
+
+ do_operation:
+ typedef int (*zend_object_do_operation_t)(
+ zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC
+ );
+
+ compare:
+ typedef int (*zend_object_compare_zvals_t)(
+ zval *result, zval *op1, zval *op2 TSRMLS_DC
+ );
+
+ The first handler is used to overload arithmetic operations. The first
+ argument specifies the opcode of the operator, result is the target zval,
+ op1 the first operand and op2 the second operand. For unary operations
+ op2 is NULL. If the handler returns FAILURE PHP falls back to the default
+ behavior for the operation.
+
+ The second handler is used to perform comparison operations with
+ non-objects. The value written into result must be an IS_LONG with value
+ -1 (smaller), 0 (equal) or 1 (greater). The return value is a SUCCESS/FAILURE
+ return code. The difference between this handler and compare_objects is
+ that it will be triggered for comparisons with non-objects and objects of
+ different types. It takes precedence over compare_objects.
+
+ Further docs in the RFC: https://wiki.php.net/rfc/operator_overloading_gmp
+
+ b. return_value_ptr now always available, RETVAL_ZVAL_FAST macros
+
+ The return_value_ptr argument to internal functions is now always set.
+ Previously it was only available for functions returning by-reference.
+ return_value_ptr can now be used to return zvals without copying them.
+ For this purpose two new macros are provided:
+
+ RETVAL_ZVAL_FAST(zv); /* analog to RETVAL_ZVAL(zv, 1, 0) */
+ RETURN_ZVAL_FAST(zv); /* analog to RETURN_ZVAL(zv, 1, 0) */
+
+ The macros behave similarly to the non-FAST variants with copy=1 and
+ dtor=0, but will try to return the zval without making a copy by utilizing
+ return_value_ptr.
+
+ c. POST data handling
+
+ The sapi_request_info's members post_data, post_data_len and raw_post_data as
+ well as raw_post_data_len have been replaced with a temp PHP stream
+ request_body.
+
+ The recommended way to access raw POST data is to open and use a php://input
+ stream wrapper. It is safe to be used concurrently and more than once.
+
+ d. Arginfo changes
+
+ The pass_rest_by_reference argument of the ZEND_BEGIN_ARG_INFO and
+ ZEND_BEGIN_ARG_INFO_EX() is no longer used. The value passed to it is ignored.
+
+ Instead a variadic argument is created using ZEND_ARG_VARIADIC_INFO():
+
+ ZEND_ARG_VARIADIC_INFO(0, name) /* pass rest by value */
+ ZEND_ARG_VARIADIC_INFO(1, name) /* pass rest by reference */
+ ZEND_ARG_VARIADIC_INFO(ZEND_SEND_PREFER_REF, name)
+ /* pass rest by prefer-ref */
+
+ ZEND_ARG_VARIADIC_INFO() should only be used for the last argument.
+
+ The following changes were applied to the zend_arg_info struct:
+
+ typedef struct _zend_arg_info {
+ const char *class_name;
+ zend_uint class_name_len;
+ zend_uchar type_hint;
+ + zend_uchar pass_by_reference;
+ zend_bool allow_null;
+ - zend_bool pass_by_reference;
+ + zend_bool is_variadic;
+ } zend_arg_info;
+
+ The following changes were applied to the zend_internal_function_info struct:
+
+ typedef struct _zend_internal_function_info {
+ zend_uint required_num_args;
+ zend_uchar _type_hint;
+ zend_bool return_reference;
+ - zend_bool pass_rest_by_reference;
+ + zend_bool _allow_null;
+ + zend_bool _is_variadic;
+ } zend_internal_function_info;
+
+ The CHECK_ARG_SEND_TYPE(), ARG_MUST_BE_SENT_BY_REF(),
+ ARG_SHOULD_BE_SENT_BY_REF() and ARG_MAY_BE_SENT_BY_REF() macros now assume
+ that the argument passed to them is a zend_function* and that it is non-NULL.
+
+ e. tsrm_virtual_cwd.h moved to zend_virtual_cwd.h
+
+ Memory allocation is now managed by emalloc/efree instead of malloc/free.
+
+ f. empty strings are interned
+
+ String created using STR_EMPTY_ALLOC() are now interned.
+ convert_to_string use STR_EMPTY_ALLOC() for zval when IS_NULL.
+ str_efree() shoud be preferred as efree() on such strings can cause memory
+ corruption.
+
+ g. Additional str_* APIs
+
+ In addition to the previously existing str_free() and str_efree() macros, the
+ following macros have been introduced to simplify dealing with potentially
+ interned strings:
+
+ str_efree_rel(str) - efree_rel() if not interned
+ str_erealloc(str, new_len) - erealloc() or emalloc+memcpy if interned
+ str_estrndup(str, len) - estrndup() if not interned
+ str_strndup(str, len) - zend_strndup() if not interned
+ str_hash(str, len) - INTERNED_HASH(str) if interned,
+ zend_hash_func(str, len+1) otherwise
+
+ h. Addition of zend_hash_reindex
+
+ A zend_hash_reindex() function with the following prototype has been added:
+
+ void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys);
+
+ If only_integer_keys==0, this function will change all keys to be continuous,
+ zero-based integers in hash order. If only_integer_keys==1 the same will be
+ done only for keys that were already integers previously, while leaving
+ string keys alone.
+
+ i. Addition of zend_hash_splice
+
+ A zend_hash_splice() macro with the following prototype has been added:
+
+ void zend_hash_splice(
+ HashTable *ht, uint nDataSize, copy_ctor_func_t pCopyConstructor,
+ uint offset, uint length,
+ void **list, uint list_count, HashTable *removed
+ );
+
+ This function performs an in-place splice operation on a hashtable:
+
+ The elements between offset and offset+length are removed and the elements in
+ list[list_count] are inserted in their place. The removed elements can be
+ optionally collected into a hashtable.
+
+ This operation reindexes the hashtable, i.e. integer keys will be zero-based
+ and sequential, while string keys stay intact. The same applies to the
+ elements inserted into the removed HT.
+
+ As a side-effect of this addition the signature of the php_splice() function
+ changed:
+
+ void php_splice(
+ HashTable *ht, zend_uint offset, zend_uint length,
+ zval ***list, zend_uint list_count, HashTable *removed TSRMLS_DC
+ )
+
+ This function now directly forwards to zend_hash_splice(), resets the
+ IAP of ht (for compatibility with the previous implementation) and resets
+ CVs if the passed hashtable is the global symbol table.
+
++ j. An additional parameter is sent to Countable::count()
++
++ That parameter denotes the $mode passed to count; it shouldn't affect any
++ userland code, but any zend_parse_parameters() used with no arguments should
++ fail. Extensions which implement Countable internally, need to accept one
++ optional long as parameter.
+
========================
2. Build system changes
========================