diff --git a/NEWS b/NEWS index 623a29b0d6c8..e507963f2059 100644 --- a/NEWS +++ b/NEWS @@ -663,6 +663,8 @@ PHP NEWS . Deprecate returning values from __construct() and __destruct(). (timwolla) . base_convert, bindex, hexdec and octdec now raise a notice when they cannot precisely convert the given number. (Sjoerd Langkemper) + . Added error_include_args INI option to make the display of function + arguments consistent in error output. (Calvin Buckley) - BCMath: . Added NUL-byte validation to BCMath functions. (jorgsowa) diff --git a/UPGRADING b/UPGRADING index 596db8fb4267..feaec16c4826 100644 --- a/UPGRADING +++ b/UPGRADING @@ -133,7 +133,7 @@ PHP 8.6 UPGRADE NOTES unchanged. Previously, NUL bytes were silently accepted: for cookie_path and cookie_domain this caused the SAPI to drop the Set-Cookie header; for cache_limiter the value was silently truncated at the NUL byte. - . A ValueError is not thrown if $name is a string containing NUL bytes in + . A ValueError is thrown if $name is a string containing NUL bytes in session_module_name(). . session_encode() now returns an empty string instead of false for empty sessions. It only returns false now when the session data could not be @@ -658,6 +658,10 @@ PHP 8.6 UPGRADE NOTES . gmp_powm() modulo-by-zero now raises a DivisionByZeroError whose message includes the function name and argument index ($modulus). +- LDAP: + . ldap_free_result() return type has been narrowed from bool to true. The + function already always returned true. + - MySQLi: . The return structure of mysqli_get_charset() no longer contains the undocumented "comment" element. The value of "charsetnr" is now set to a @@ -819,7 +823,7 @@ PHP 8.6 UPGRADE NOTES . StreamPollHandle - URI: - . Uri\Rfc3986\UriBuilder + . Uri\Rfc3986\UriBuilder and Uri\WhatWg\UrlBuilder RFC: https://wiki.php.net/rfc/uri_followup#uri_building ======================================== @@ -913,6 +917,15 @@ PHP 8.6 UPGRADE NOTES 11. Changes to INI File Handling ======================================== +- Core: + . The error_include_args INI option has been added to make the display of + function arguments consistent in errors; it is off by default. Previously, + some functions shown a parameter in the error that was up to each call to + the internal error function. Now, all parameters as were actually passed to + the function will be displayed. This uses the same infrastructure as stack + traces, so i.e. sensitive parameters will not be displayed, and strings + will be truncated according to zend.exception_string_param_max_len. + - Mbstring: . The mbstring.detect_order INI directive now updates the internal detection order when changed at runtime via ini_set(). Previously, runtime changes @@ -1004,6 +1017,7 @@ PHP 8.6 UPGRADE NOTES . Reduced temporary allocations when iterating Phar directories. - Standard: + . Improved performance of sorting single-element arrays. . Improved performance of array_fill_keys(). . Improved performance of array_intersect(). . Improved performance of array_map() with multiple arrays passed. diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 99406f9e4192..84751a02e7c0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2997,9 +2997,17 @@ static void zend_hash_sort_internal(HashTable *ht, sort_func_t sort, bucket_comp IS_CONSISTENT(ht); - if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { - /* Doesn't require sorting */ - return; + if (ht->nNumOfElements <= 1) { + if (!renumber || ht->nNumOfElements == 0) { + /* Doesn't require sorting */ + return; + } + if (sort == zend_sort && HT_IS_PACKED(ht) && HT_IS_WITHOUT_HOLES(ht)) { + /* The single element already has the expected index. */ + ht->nInternalPointer = 0; + ht->nNextFreeElement = 1; + return; + } } if (HT_IS_PACKED(ht)) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 1181bee29fae..c7cdbe95866e 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -312,7 +312,12 @@ static zend_always_inline void ZEND_FASTCALL zend_hash_sort(HashTable *ht, bucke * trigger user code. It will ensure the user code cannot free the array during * sorting. */ static zend_always_inline void zend_array_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber) { - zend_array_sort_ex(ht, zend_sort, compare_func, renumber); + /* zend_sort() cannot invoke the comparator for at most one element. */ + if (ht->nNumOfElements <= 1) { + zend_hash_sort_ex(ht, zend_sort, compare_func, renumber); + } else { + zend_array_sort_ex(ht, zend_sort, compare_func, renumber); + } } static zend_always_inline uint32_t zend_hash_num_elements(const HashTable *ht) { diff --git a/ext/standard/tests/array/sort/sort_single_element.phpt b/ext/standard/tests/array/sort/sort_single_element.phpt new file mode 100644 index 000000000000..d7d63e98c733 --- /dev/null +++ b/ext/standard/tests/array/sort/sort_single_element.phpt @@ -0,0 +1,57 @@ +--TEST-- +Sorting single-element arrays does not invoke the comparison function +--FILE-- + $b; +}; + +$array = [42]; +// Keep the array packed and without holes, but leave the next free index at 11. +$array[10] = 99; +unset($array[10]); +next($array); +var_dump(usort($array, $compare)); +var_dump($array, key($array)); +$array[] = 43; +var_dump($array); + +$array = ['answer' => 42]; +next($array); +var_dump(usort($array, $compare)); +var_dump($array, key($array)); +$array[] = 43; +var_dump($array); + +var_dump($calls); + +?> +--EXPECT-- +bool(true) +array(1) { + [0]=> + int(42) +} +int(0) +array(2) { + [0]=> + int(42) + [1]=> + int(43) +} +bool(true) +array(1) { + [0]=> + int(42) +} +int(0) +array(2) { + [0]=> + int(42) + [1]=> + int(43) +} +int(0)