PHP 8.6 INTERNALS UPGRADE NOTES

1. Internal API changes

2. Build system changes

3. Module changes

4. OpCode changes

5. SAPI changes

========================
1. Internal API changes
========================

- Breaking changes:
  . String formatting functions now support the custom conversion specifiers
    'pS' (zend_string*) and 'pp' (same as 'p'). Following the 'p' specifier with
    an alpha-numeric character other than 'S' or 'p' is now an error.

    Examples:

    zend_string *str;
    zend_spprintf("%pS", str);  // valid, same as "%S"
    zend_spprintf("%pp", str);  // valid, same as "%p"
    zend_spprintf("%pA", str);  // invalid
    zend_spprintf("%ppA", str); // valid, same as zend_spprintf("%p%c", str, 'A')

- Removed:
  . The misnamed ZVAL_IS_NULL() has been removed. Use Z_ISNULL() instead.
  . The zval_is_true() alias of zend_is_true() has been removed. Call
    zend_is_true() directly instead.
  . The _zval_get_*() compatibility macros for PHP 7.2 have been removed
    call the variant without the leading underscore instead.
    Affected: _zval_get_long, _zval_get_double, _zval_get_string,
    _zval_get_long_func, _zval_get_double_func, _zval_get_string_func
  . CHECK_ZVAL_NULL_PATH() and CHECK_NULL_PATH() have been removed, use
    zend_str_has_nul_byte(Z_STR_P(...)) and zend_char_has_nul_byte()
    respectively.
  . ZEND_LTOA() (and ZEND_LTOA_BUF_LEN) has been removed, as it was
    unsafe. Directly use ZEND_LONG_FMT with a function from the
    printf family.
  . The zval_dtor() alias of zval_ptr_dtor_nogc() has been removed.
    Call zval_ptr_dtor_nogc() directly instead.
  . The internal zend_copy_parameters_array() function is no longer exposed.
  . The internal zend_hash_minmax() function is no longer exposed. Scan the
    HashTable directly and use zend_compare() for value comparisons instead.
  . The zend_make_callable() function has been removed, if a callable zval
    needs to be obtained use the zend_get_callable_zval_from_fcc() function
    instead. If this was used to store a callable, then an FCC should be
    stored instead.
  . The zend_exception_save() and zend_exception_restore() functions were
    removed.
  . The zend_set_hash_symbol() API has been removed.
  . The WRONG_PARAM_COUNT and ZEND_WRONG_PARAM_COUNT() macros have been
    removed. Call zend_wrong_param_count(); followed by RETURN_THROWS();
    instead.
  . PHP_HAVE_STREAMS macro removed from <php.h>.
  . The INI_STR(), INI_INT(), INI_FLT(), and INI_BOOL() macros have been
    removed. Instead new zend_ini_{bool|long|double|str|string}_literal()
    macros have been added. This fixes an internal naming inconsistency as
    "str" usually means zend_string*, and "string" means char*.
    However INI_STR() returned a char*
  . The INI_ORIG_{INT|STR|FLT|BOOL}() macros have been removed as they are
    unused. If this behaviour is required fall back to the zend_ini_*
    functions.
  . The unused ZEND_AST_PARENT_PROPERTY_HOOK_CALL has been removed.
  . The EMPTY_SWITCH_DEFAULT_CASE() macro has been removed. Use
    default: ZEND_UNREACHABLE(); instead.
  . The ZEND_RESULT_CODE type has been removed. Use zend_result directly.
  . The zend_parse_parameters_none_throw(), zend_parse_parameters_throw(),
    and ZEND_PARSE_PARAMS_THROW have been removed due to being misleading,
    since ZPP always throws, unless ZEND_PARSE_PARAMS_QUIET is given. Use
    the non-throw versions.
  . The XtOffsetOf() alias of C’s offsetof() macro has been removed. Use
    offsetof() directly.
  . The deprecated Z_COPYABLE(), Z_COPYABLE_P(), Z_OPT_COPYABLE(), and
    Z_OPT_COPYABLE_P() macros have been removed. Check for IS_ARRAY directly.
  . The deprecated Z_IMMUTABLE(), Z_IMMUTABLE_P(), Z_OPT_IMMUTABLE(), and
    Z_OPT_IMMUTABLE_P() macros have been removed. Check for
    IS_ARRAY && !REFCOUNTED directly.
  . The unused Z_GC_*() macros have been removed. Use the corresponding
    GC_*() macro on the result of Z_COUNTED().
  . The zend_binary_zval_strcmp() and zend_binary_zval_strncmp() functions
    have been removed, because they are unsafe by relying on the zvals
    having a specific type. Use zend_binary_strcmp() / zend_binary_strncmp(),
    string_compare_function() or similar instead.
  . The OPENBASEDIR_CHECKPATH() compatibility macro has been removed, instead
    use php_check_open_basedir() directly.
  . The Z_CONSTANT(), Z_CONSTANT_P(), Z_OPT_CONSTANT(), and
    Z_OPT_CONSTANT_P() macros have been removed. Check for IS_CONSTANT_AST
    directly.
  . The {_}php_stream_fopen_with_path() functions have been removed as they are
    unused.
  . The php_error_docref1() and php_error_docref2() functions have been
    removed, instead rely on the error_include_args INI option to show the
    arguments to functions in a consistent manner.
  . The following PHP stream functions prefixed with _ have been removed,
    and the macro without it has become the canonical function name:
    * _php_stream_cast()
    * _php_stream_free_enclosed()
    * _php_stream_free()
    * _php_stream_seek()
    * _php_stream_tell()
    * _php_stream_read()
    * _php_stream_write()
    * _php_stream_fill_read_buffer()
    * _php_stream_printf()
    * _php_stream_eof()
    * _php_stream_getc()
    * _php_stream_putc()
    * _php_stream_flush()
    * _php_stream_sync()
    * _php_stream_get_line()
    * _php_stream_puts()
    * _php_stream_stat()
    * _php_stream_mkdir()
    * _php_stream_rmdir()
    * _php_stream_readdir()
    * _php_stream_set_option()
    * _php_stream_get_url_stream_wrappers_hash()
    * _php_get_stream_filters_hash()
    * _php_stream_mmap_unmap()
    * _php_stream_mmap_unmap_ex()
    * _php_stream_filter_prepend()
    * _php_stream_filter_append()
    * _php_stream_filter_flush()
  . The PHP stream function _php_stream_stat_path() has been renamed to
    php_stream_stat_path_ex()
  . The PHP stream function _php_stream_scandir() was removed,
    insted the PHP macro php_stream_scandir() is now a function as the
    flags parameter was never used.
  . The PHP stream function _php_stream_flush() was removed,
    instead the PHP macro php_stream_flush() is now a proper function.
  . The zend_save_error_handling() function was removed.
  . The zend_parse_parameter() function has been removed, use one fo the
    zend_parse_arg_TYPE() APIs instead.
  . The zend_is_countable() function was removed.

- Changed:
  . Internal functions that return by reference are now expected to
    automatically unwrap references when the result of the call is stored in an
    IS_TMP_VAR variable. This may be achieved by calling the
    zend_return_unwrap_ref() function.
  . ZEND_AST_METHOD_REFERENCE has been renamed to
    ZEND_AST_TRAIT_METHOD_REFERENCE.
  . Functions using zend_forbid_dynamic_call() *must* be flagged with
    ZEND_ACC2_FORBID_DYN_CALLS (@forbid-dynamic-calls in stubs). In debug
    builds, failing to include that flag will lead to assertion failures.
  . The zend_get_call_trampoline_func() API now takes the __call or
    __callStatic zend_function* instead of a CE and a boolean argument.
  . ZSTR_INIT_LITERAL(), zend_string_starts_with_literal(), and
    zend_string_starts_with_literal_ci() now support strings containing NUL
    bytes. Passing non-literal char* is no longer supported.
  . The zend_active_function{_ex}() functions now return a const zend_function
    pointer.
  . zend_function.arg_info is now always a zend_arg_info*. Before, it was a
    zend_internal_arg_info on internal functions, unless the
    ZEND_ACC_USER_ARG_INFO flag was set.
  . ZEND_INI_GET_ADDR() is now a void* pointer instead of a char* pointer. This
    more correctly represents the generic nature of the returned pointer and
    allows to remove explicit casts, but possibly breaks pointer arithmetic
    performed on the result.
  . The zend_dval_to_lval_cap() function no longer takes a second
    zend_string* parameter.
  . EG(in_autoload) was renamed to EG(autoload_current_classnames) and no
    longer is a pointer, but a directly embedded HashTable struct.
  . Extended php_stream_filter_ops with seek method.
  . php_print_info_htmlhead() now takes a title argument.
  . zend_argument_error_variadic() now takes a new 'function' parameter.
  . The param argument in the php_verror() function has been removed.
  . The php_stream_wrapper_log_error() signature changed from
    (wrapper, options, fmt, ...) to
    (wrapper, context, options, severity, terminating, code, fmt, ...).
    To keep the previous behaviour pass NULL for the context, or the context at
    hand if there is one, E_WARNING for the severity, and
    ZEND_ENUM_StreamErrorCode_Generic for the code. terminating should be true
    only if the error aborts the operation.
  . zend_create_closure(), zend_create_fake_closure() and
    zend_create_partial_closure() now take the bound $this as a zend_object*
    instead of a zval*. Accordingly, zend_get_closure_this_ptr() now returns
    that zend_object*, or NULL when the closure is unbound, instead of a
    zval* that is IS_UNDEF when the closure is unbound.

- Added:
  . New zend_class_entry.ce_flags2 and zend_function.fn_flags2 fields were
    added, given the primary flags were running out of bits.
  . Added zend_hash_str_lookup().
  . Added zend_ast_call_get_args() to fetch the argument node from any call
    node.
  . Added Z_PARAM_ENUM().
  . Added PHP_GD_Z_PARAM_ARRAY_HT_OR_DOUBLE() in ext/gd to parse array|float
    arguments into either a HashTable pointer or a double.
  . Added zend_enum_fetch_case_id().
  . Added zend_enum_get_case_by_id().
  . Added zend_bin2hex() and zend_bin2hex_str() as helper functions to remove
    dependencies on /ext/hash in various extensions.
  . Added a C23_ENUM() helper macro to define forward-compatible fixed-size
    enums.
  . Added zend_fcall_info.consumed_args together with
    zend_fci_consumed_arg(), which allows moving a selected callback argument
    instead of copying it in zend_call_function(). Currently only a single
    consumed argument is supported.
  . Added ZEND_CONTAINER_OF().
  . Added zend_reflection_property_set_raw_value_without_lazy_initialization(),
    zend_reflection_property_set_raw_value() to expose the functionality of
    ReflectionProperty::setRawValueWithoutLazyInitialization() and
    ReflectionProperty::setRawValue() to C extensions.
  . Added zend_object_set_properties_reinitable() to centralise temporarily
    allowing reinitialisation of initialised readonly properties during
    controlled operations such as cloning and unserialisation.
  . Added zend_argument_error_ex(), zend_argument_type_error_ex(),
    zend_argument_value_error_ex().
  . Added zend_ast_dup().
  . Added zend_compile_ast().
  . Added zend_check_type_ex().
  . Added zend_create_partial_closure().
  . Added a new IO copy API in <php_io.h>. php_io_copy() copies bytes between
    file descriptors using the most efficient platform primitive available
    (sendfile, splice, copy_file_range, TransmitFile), and is now used by
    php_stream_copy_to_stream_ex(). The mmap-based copy fallback was removed.
  . Added zend_string_equals_cstr_ci().
  . Added zend_cstr_append_char(), zend_cstr_concat(), and
    zend_cstr_concat3() as helper functions to allocate NUL-terminated raw C
    strings from one or more buffers.
  . Added zend_string_ends_with() and related variants.
  . Added trait support for internal classes.
  . Added do_php_cli().

========================
2. Build system changes
========================

- Abstract:
  . run-tests.php now runs in parallel by default, using up to 10 automatically
    detected workers. Pass -j1 for sequential execution. --asan, --msan, and
    Valgrind default to at most two workers.
  . Minimum required PHP version found on the host system for running scripts
    like build/gen_stub.php during development has been updated from 7.4 to 8.1.
  . build/gen_stub.php may now generate a _decl.h file in addition to
    the _arginfo.h file, if the stub declares enums and is annotated with
    @generate-c-enums. For each enum the file will contain a C enum. Enum
    values can be compared to the result of
    zend_enum_fetch_case_id(zend_object*).

- Unix build system changes:
  . scripts/dev/update-autoconf.sh has been added to update config.*/libtool.
  . libtool has been upgraded to 2.5.4 (serial 63), which fixes many bugs.
  . As part of the upgrade to the new libtool:
    . libtool is now spread across multiple files. phpize has been updated to
      handle this.
    . On macOS, libtool now uses -undefined dynamic_lookup for shared objects,
      instead of -undefined suppress -flat_namespace.
    . --with-pic is now --enable-pic. The old flag will result in an error.
  . Symbol HAVE_ST_BLOCKS has been removed from php_config.h (use
    HAVE_STRUCT_STAT_ST_BLOCKS).
  . Added a new configure option --disable-apache2-conf to prevent apxs from
    editing httpd.conf during installation.

- Windows build system changes:
  . Function SETUP_OPENSSL() doesn't accept 6th argument anymore and doesn't
    define the HAVE_OPENSSL_SSL_H preprocessor macro anymore.
  . Function SETUP_SQLITE3() doesn't define HAVE_SQLITE3_H and HAVE_SQLITE3EXT_H
    preprocessor macros anymore.
  . Added a new function CHECK_HEADER() which is intended to be used instead of
    the CHECK_HEADER_ADD_INCLUDE().

- Embed:
  . The CLI SAPI can not be disabled when building the embed SAPI
    (--enable-embed is incompatible with --disable-cli).

========================
3. Module changes
========================

- ext/date:
  . php_idate() now returns the result state, and moves the return value into an
    out parameter.

- ext/intl:
  . Added intl_icu_compat.h with helpers and feature macros for ICU
    version-specific API differences. Code in ext/intl should use the
    intl_icu_compat_* helpers and INTL_ICU_HAS_* macros instead of adding
    direct U_ICU_VERSION_* guards for supported ICU API variants.
  . The internal grapheme_get_break_iterator() helper no longer accepts a
    stack buffer argument; pass only the UErrorCode* status argument.
  . Added PHP_INTL_FUNCTION_WITH_ERROR_RESET() for procedural functions that
    reset the global error. Use it instead of PHP_FUNCTION() followed by a
    manual intl_error_reset(NULL) call.
  . IC_METHOD() now resets the global error before entering the method
    implementation. IntlChar methods should no longer reset it manually.

- ext/mbstring:
  . Added GB18030-2022 to default encoding list for zh-CN.

- ext/mysqlnd:
  . Dropped session_options parameter from all methods in mysqlnd_auth.
    The same information is present in conn->options and should be used
    instead.
  . Removed charsets plugin.

- ext/session:
  . php_session_flush() now returns a bool rather than a zend_result.
  . The mod_user_names global has been removed.
  . The mod_user_uses_object_methods_as_handlers global has been added,
    it indicates whether the session handlers are methods of an object or not.
  . Removed session_adapt_url().
  . PS_OPEN_ARGS is now defined as
    `void **mod_data, zend_string *save_path, zend_string *session_name`
    rather than
    `void **mod_data, const char *save_path, const char *session_name`
  . PS_FUNCS() now includes the PS_VALIDATE_SID_FUNC()
  . PS_MOD() now requires that the PS_CREATE_SID_FUNC() and
    PS_VALIDATE_SID_FUNC() functions are defined.
  . PS_FUNCS_SID() and PS_MOD_SID() have been removed.
    Either use PS_FUNCS()/PS_MOD() or PS_FUNCS_UPDATE_TIMESTAMP()/
    PS_MOD_UPDATE_TIMESTAMP() if timestamp support exists.

- ext/standard:
  . _php_error_log() now has a formal return type of zend_result.
  . _php_error_log() now accepts zend_string* values instead of char*.
  . _php_error_log_ex() has been removed.
  . php_mail()'s extra_cmd parameter is now a zend_string*.
  . The php_math_round_mode_from_enum() function now takes a
    zend_enum_RoundingMode parameter.

- ext/uri:
  . The value parameter of the php_uri_property_handler_write callback is now
    const zval * instead of zval *, reflecting that write handlers must
    not modify the input zval.

- ext/xml:
  . Removed the XML_ExpatVersion() libxml compatibility wrapper,
    as it was unused.
  . Removed the XML_GetCurrentByteCount() libxml compatibility wrapper,
    as it was unused and could return the wrong result.

========================
4. OpCode changes
========================

- Added ZEND_TYPE_ASSERT to check a value's type against the parameter
  type of a function, throwing a TypeError on failure as if the function
  was called. Used in optimizations that elide function calls.

========================
5. SAPI changes
========================

- SAPIs should explicitly release a thread's resources by calling
  ts_free_thread() before terminating it. tsrm_shutdown() can only release the
  resources of the calling thread, for resources allocated with
  ts_allocate_tls_id().

- AG and SCNG are now allocated with ts_allocate_tls_id() and live in native
  __thread storage on ZTS builds.

- php-cli functionality is now available in embed builds via the do_php_cli()
  function.
