## Other Changes

### Core changes

#### Closures

Closure names have been adjusted to include the parent function's name and the line of definition to make them easier to distinguish, for example within stack traces.

#### Fibers

Fiber switching during destructor execution is now allowed. It was previously blocked due to conflicts with garbage collection.

Destructors may now be executed in a separate Fiber:

When garbage collection is triggered in a Fiber, destructors called by the GC are executed in a separate Fiber: the gc_destructor_fiber. If this Fiber suspends, a new one is created to execute the remaining destructors. The previous gc_destructor_fiber is not referenced anymore by the GC and may be collected if it's not referenced anywhere else. Objects whose destructor is suspended will not be collected until the destructor returns or the Fiber is collected.

#### Output Handlers

Output handler status flags passed to the `flags` parameter of ob_start() are now cleared.

output_add_rewrite_var() now uses `url_rewriter.hosts` instead of `session.trans_sid_hosts` for selecting hosts that will be rewritten.

### Changes in SAPI Modules

#### apache2handler

Support for EOL Apache 2.0 and 2.2 has been removed. Minimum required Apache version is now 2.4.

#### CLI

The builtin server looks for an index file recursively by traversing parent directories in case the specified file cannot be located. This process was previously skipped if the path looked like it was referring to a file, i.e. if the last path component contained a period. In that case, a 404 error was returned. The behavior has been changed to look for an index file in all cases.

#### FPM

Flushing headers without a body will now succeed.

Status page has a new field to display a memory peak.

The /dev/poll `events.mechanism` setting for Solaris/Illumos had been retired.

### Changed Functions

#### Core

trigger_error() and user_error() now have a return type of true instead of bool.

#### DOM

DOMDocument::registerNodeClass() now has a tentative return type of true instead of bool. It could only ever return `true` in practice.

#### Hash

hash_update() now has a tentative return type of true instead of bool. It could only ever return `true` in practice.

#### Intl

`NumberFormatter::ROUND_TOWARD_ZERO` and `NumberFormatter::ROUND_AWAY_FROM_ZERO` have been added as aliases for `NumberFormatter::ROUND_DOWN` and `NumberFormatter::ROUND_UP` to be consistent with the new `PHP_ROUND_*` modes.

ResourceBundle::get() now has a tentative return type of `ResourceBundle|array|string|int|null`.

The idn_to_ascii() and idn_to_utf8() functions now always throw ValueErrors if the `domain` name is empty or too long.

The idn_to_ascii() and idn_to_utf8() functions now always throw ValueError if the `variant` parameter is not `INTL_IDNA_VARIANT_UTS46`.

#### LibXML

libxml_set_streams_context() now immediately throws a TypeError when a non-stream-context resource is passed to the function, instead of throwing later when the stream context is used.

#### MBString

The behavior of mb_strcut() is more consistent now on invalid UTF-8 and UTF-16 strings. There is no behavioural change for valid UTF-8 and UTF-16 strings.

#### ODBC

The `row` of odbc_fetch_object(), odbc_fetch_array(), and odbc_fetch_into() now have a default value of `null`, consistent with odbc_fetch_row(). Previously, the default values were `-1`, `-1`, and `0`, respectively.

#### OpenSSL

The `extra_attributes` in openssl_csr_new() sets the CSR attributes instead of subject DN, which incorrectly done previously.

The `dn` in openssl_csr_new() allows setting an array of values for a single entry.

New `serial_hex` added to openssl_csr_sign() to allow setting serial numbers in the hexadecimal format.

Parsing ASN.1 UTCTime with openssl_x509_parse() fails if seconds are omitted for OpenSSL version below 3.2 (`-1` is returned for such fields). OpenSSL version above 3.3 did not load such certificates already.

#### PDO

It is now possible to fetch the value of the `PDO::ATTR_STRINGIFY_FETCHES` attribute with PDO::getAttribute().

A new `PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE` has been added to retrieve the memory usage of query results with PDO::getAttribute() for drivers that support it.

#### PDO_FIREBIRD

It is now possible to fetch the value of the `FB_ATTR_DATE_FORMAT`, `FB_ATTR_TIME_FORMAT`, `FB_ATTR_TIMESTAMP_FORMAT`, attributes with PDO::getAttribute().

Added new attributes to specify transaction isolation level and access mode. Five constants relating to this functionality have been added:

- `Pdo\Firebird::TRANSACTION_ISOLATION_LEVEL`
- `Pdo\Firebird::READ_COMMITTED`
- `Pdo\Firebird::REPEATABLE_READ`
- `Pdo\Firebird::SERIALIZABLE`
- `Pdo\Firebird::WRITABLE_TRANSACTION`

When using persistent connections, there is now a liveliness check in the constructor.

The content that is built changes depending on the value of `FB_API_VER` in ibase.h. A new static method Pdo\Firebird::getApiVersion() can be used to obtain this information. This information is also now referenced in phpinfo().

Five new data types are now available: `INT128`, `DEC16`, `DEC34`, `TIMESTAMP_TZ`, `TIME_TZ` . These are available starting with Firebird 4.0.

#### PDO_MYSQL

It is now possible to fetch the value of the `PDO::ATTR_FETCH_TABLE_NAMES` attribute with PDO::getAttribute().

#### PDO_PGSQL

Support retrieving the memory usage of queries for `PDO::PGSQL_ATTR_RESULT_MEMORY_SIZE`.

If the column is of type `FLOAT4OID` or `FLOAT8OID` the value will now be returned as a float instead of a string.

#### PGSQL

The `conditions` parameter of pg_select() is now optional and accepts an empty array.

#### Phar

The Phar::setAlias(), Phar::setDefaultStub() methods now have a tentative return type of true instead of bool.

#### POSIX

posix_isatty() now sets the error number when the file descriptor/stream argument is invalid.

#### Reflection

ReflectionGenerator::getFunction() may now be called after the generator finished executing.

#### Sockets

The `backlog` parameter of socket_create_listen() now has a default value of `SOMAXCONN`. Previously, it was `128`.

#### Sodium

The sodium_crypto_aead_aes256gcm_()* functions are now available on aarch64 CPUs with the ARM cryptographic extensions.

#### SPL

The SplPriorityQueue::insert(), SplPriorityQueue::recoverFromCorruption(), SplHeap::insert(), SplHeap::recoverFromCorruption() methods now have a tentative return type of true instead of bool.

SplObjectStorage now implements SeekableIterator.

#### Standard

The default `'cost'` value for the `PASSWORD_BCRYPT` hashing algorithm for password_hash() has been increased from `10` to `12`.

debug_zval_dump() now indicates whether an array is packed.

long2ip() now has a return type of string instead of `string|false`.

highlight_string() now has a return type of string|true instead of `string|bool`.

print_r() now has a return type of string|true instead of `string|bool`.

##### Rounding with round()

The `mode` parameter of the round() function has been widened to `RoundingMode|int`, accepting instances of a new RoundingMode enum.

Four new modes have been added to the round() function: RoundingMode::PositiveInfinity, RoundingMode::NegativeInfinity, RoundingMode::TowardsZero, RoundingMode::AwayFromZero

The internal implementation for rounding to integers has been rewritten to be easier to verify for correctness and to be easier to maintain. Some rounding bugs have been fixed as a result of the rewrite. For example previously rounding `0.49999999999999994` to the nearest integer would have resulted in `1.0` instead of the correct result `0.0`. Additional inputs might also be affected and result in different outputs compared to earlier PHP versions.

Fixed a bug caused by "pre-rounding" of the round() function. Previously, using "pre-rounding" to treat a value like `0.285` (actually `0.28499999999999998`) as a decimal number and round it to `0.29`. However, "pre-rounding" incorrectly rounds certain numbers, so this fix removes "pre-rounding" and changes the way numbers are compared, so that the values are correctly rounded as decimal numbers.

The maximum precision that can be handled by round() has been extended by one digit. For example, `round(4503599627370495.5)` returned in `4503599627370495.5`, but now returns `4503599627370496`.

### Other Changes to Extensions

#### cURL

The minimum libcurl version required is now 7.61.0.

The `CURLOPT_DNS_USE_GLOBAL_CACHE` option no longer has any effect, and is silently ignored. This underlying feature was deprecated in libcurl 7.11.1, and removed in libcurl 7.62.0.

#### GMP

Casting a GMP object to bool is now possible instead of emitting a `E_RECOVERABLE_ERROR`. The casting behaviour is overloaded such that a GMP object representing the value `0` is cast to `false`.

#### LibXML

The minimum libxml2 version required is now 2.9.4.

#### Intl

The behaviour of Intl class has been normalized to always throw Error exceptions when attempting to use a non-initialized object, or when cloning fails.

#### MBString

Unicode data tables have been updated to Unicode 16.0.

#### MySQLnd

Support for the new VECTOR data type from MySQL 9.

#### OpenSSL

The minimum OpenSSL version required is now 1.1.1.

#### PDO_PGSQL

The minimum libpq version required is now 10.0.

#### PGSQL

The minimum libpq version required is now 10.0.

#### SPL

Out of bounds accesses in SplFixedArray now throw exceptions of type OutOfBoundsException instead of RuntimeException. Because OutOfBoundsException is a child class of RuntimeException no behavioural changes are exhibited when attempting to catch those exceptions.

#### XSL

The typed properties XSLTProcessor::$cloneDocument and XSLTProcessor::$doXInclude are now declared.

#### Zlib

The minimum zlib version required is now 1.2.11.

### Performance

#### Core

Improved the performance of floating point number parsing and formatting in ZTS builds under highly concurrent loads. This affects the printf() family of functions as well as serialization functions such as json_encode(), or serialize().

sprintf() using only `%s` and `%d` specifiers will be compiled into the equivalent string interpolation, avoiding the overhead of a function call and repeatedly parsing the format string.

#### BCMath

Improved performance of number conversions and operations.

#### DOM

The performance of DOMNode::C14N() is greatly improved for the case without an xpath query. This can give a time improvement of easily two order of magnitude for documents with tens of thousands of nodes.

Improved performance and reduce memory consumption of XML serialization.

Reduced memory usage of node classes.

#### FTP

Improved the performance of FTP uploads up to a factor of 10x for large uploads.

#### Hash

Added SSE2 and SHA-NI implementations of SHA-256. This improves the performance on supported CPUs by ~1.3x (SSE2), and 3x - 5x (SHA-NI). Credit to Colin Percival / Tarsnap for this optimization.

#### MBString

mb_strcut() is much faster now for UTF-8 and UTF-16 strings.

Looking up mbstring encoding names is much faster now.

The performance of converting SJIS-win to Unicode is greatly improved.

#### MySQLnd

Improved the performance of MySQLnd quoting.

#### PCRE

Improved the performance of named capture groups.

#### Random

Improved the performance of Random\Randomizer, with a specific focus on the Random\Randomizer::getBytes(), and Random\Randomizer::getBytesFromString() methods.

#### SimpleXML

Improved performance and reduce memory consumption of XML serialization.

#### Standard

The performance of strspn() and strcspn() is greatly improved. They now run in linear time instead of being bounded by quadratic time.

Improved the performance of strpbrk().

get_browser() is much faster now, up to 1.5x - 2.5x for some test cases.

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open