From f38058d22321cf6c297a2098a890afaa58329354 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 9 Mar 2026 13:29:06 -0400 Subject: [PATCH 01/10] ext/pcntl: Bump num_signals to uint16_t (#21347) On AIX, NSIG is def'd as SIGMAX64+1, and SIGMAX64 itself is def'd as 255: ``` $ grep -Rw SIGMAX64 /QOpenSys/usr/include/ /QOpenSys/usr/include/sys/signal.h:#define SIGMAX64 255 /QOpenSys/usr/include/sys/signal.h:#define SIGMAX SIGMAX64 /QOpenSys/usr/include/sys/signal.h:#define NSIG64 (SIGMAX64+1) ``` ...this causes an overflow when we set num_signals from the value of NSIG, per GCC: ``` /rpmbuild/BUILD/php-8.5.3/ext/pcntl/pcntl.c:216:25: warning: large integer implicitly truncated to unsigned type [-Woverflow] PCNTL_G(num_signals) = NSIG; ^~~~ ``` ...when we try to use pcntl to i.e. install a signal handler, we get an error from pcntl: ``` Fatal error: Uncaught ValueError: pcntl_signal(): Argument #1 ($signal) must be less than 0 in phar:///QOpenSys/pkgs/bin/composer/vendor/seld/signal-handler/src/SignalHandler.php:491 ``` The easiest way to deal with this silly AIX behaviour is to just promote the storage size. --- ext/pcntl/php_pcntl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/pcntl/php_pcntl.h b/ext/pcntl/php_pcntl.h index f2cc0d59195f..3757c7d9219e 100644 --- a/ext/pcntl/php_pcntl.h +++ b/ext/pcntl/php_pcntl.h @@ -46,7 +46,8 @@ ZEND_BEGIN_MODULE_GLOBALS(pcntl) bool processing_signal_queue; volatile bool pending_signals; bool async_signals; - uint8_t num_signals; + /* some OSes define NSIG to be > UINT8_MAX */ + uint16_t num_signals; int last_error; struct php_pcntl_pending_signal *head, *tail, *spares; ZEND_END_MODULE_GLOBALS(pcntl) From 06f9389d69121e895ce05281c6260fde49a8449f Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Mon, 9 Mar 2026 14:31:20 -0300 Subject: [PATCH 02/10] Update NEWS for pcntl fix [skip ci] --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index b7d4c1eee441..dbdb7c906c76 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,10 @@ PHP NEWS . Fixed bug GH-21052 (Preloaded constant erroneously propagated to file-cached script). (ilutov) +- PCNTL: + . Fixed signal handler installation on AIX by bumping the storage size of the + num_signals global. (Calvin Buckley) + - PCRE: . Fixed re-entrancy issue on php_pcre_match_impl, php_pcre_replace_impl, php_pcre_split_impl, and php_pcre_grep_impl. (David Carlier) From 0155b50984d8f32490718d46b43f145b4a90500d Mon Sep 17 00:00:00 2001 From: ndossche <7771979+ndossche@users.noreply.github.com> Date: Mon, 9 Mar 2026 20:45:07 +0100 Subject: [PATCH 03/10] phar: Fix const-generic compile warnings --- ext/phar/phar_object.c | 8 +++----- ext/phar/tar.c | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 2d8ee9c435ed..d4b084217b5b 100644 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -46,9 +46,8 @@ static zend_class_entry *phar_ce_entry; static int phar_file_type(const HashTable *mimes, const char *file, char **mime_type) /* {{{ */ { - char *ext; phar_mime_type *mime; - ext = strrchr(file, '.'); + const char *ext = strrchr(file, '.'); if (!ext) { *mime_type = "text/plain"; /* no file extension = assume text/plain */ @@ -347,10 +346,9 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len, /* post-process REQUEST_URI and retrieve the actual request URI. This is for cases like http://localhost/blah.phar/path/to/file.php/extra/stuff which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */ -static void phar_postprocess_ru_web(const char *fname, size_t fname_len, const char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ +static void phar_postprocess_ru_web(char *fname, size_t fname_len, char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */ { - const char *e = entry + 1; - char *u = NULL, *u1 = NULL, *saveu = NULL; + char *e = entry + 1, *u1 = NULL, *u = NULL, *saveu = NULL; size_t e_len = *entry_len - 1, u_len = 0; phar_archive_data *pphar; diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 6a3840b3671c..0c93de243adc 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -105,7 +105,8 @@ bool phar_is_tar(const char *buf, const char *fname) /* {{{ */ tar_header *header = (tar_header *) buf; uint32_t checksum = phar_tar_number(header->checksum, sizeof(header->checksum)); bool is_tar; - char save[sizeof(header->checksum)], *bname; + char save[sizeof(header->checksum)]; + const char *bname; /* assume that the first filename in a tar won't begin with Date: Tue, 10 Mar 2026 05:28:50 +0800 Subject: [PATCH 04/10] RFC: Add Form Feed in Trim Functions (#20788) RFC: https://wiki.php.net/rfc/trim_form_feed Resolves GH-20783. --- NEWS | 2 ++ UPGRADING | 2 ++ ext/standard/basic_functions.stub.php | 8 ++++---- ext/standard/basic_functions_arginfo.h | 4 ++-- ext/standard/basic_functions_decl.h | 8 ++++---- ext/standard/string.c | 19 +++++++++---------- ext/standard/tests/strings/trim.phpt | 6 ++++++ 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/NEWS b/NEWS index 482dfcb09134..ae0f6f3e8ff5 100644 --- a/NEWS +++ b/NEWS @@ -122,6 +122,8 @@ PHP NEWS - Standard: . Fixed bug GH-19926 (reset internal pointer earlier while splicing array while COW violation flag is still set). (alexandre-daubois) + . Added form feed (\f) in the default trimmed characters of trim(), rtrim() + and ltrim(). (Weilin Du) . Invalid mode values now throw in array_filter() instead of being silently defaulted to 0. (Jorg Sowa) . Fixed bug GH-21058 (error_log() crashes with message_type 3 and diff --git a/UPGRADING b/UPGRADING index 732d6f1d4859..595a49e41e4d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -47,6 +47,8 @@ PHP 8.6 UPGRADE NOTES - Standard: . Invalid mode values now throw in array_filter() instead of being silently defaulted to 0. + . Form feed (\f) is now added in the default trimmed characters of trim(), + rtrim() and ltrim(). RFC: https://wiki.php.net/rfc/trim_form_feed ======================================== 2. New Features diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6fa0d47c7bd7..6d0c565fc2d4 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -2318,16 +2318,16 @@ function strcoll(string $string1, string $string2): int {} * @frameless-function {"arity": 1} * @frameless-function {"arity": 2} */ -function trim(string $string, string $characters = " \n\r\t\v\0"): string {} +function trim(string $string, string $characters = " \f\n\r\t\v\0"): string {} /** @compile-time-eval */ -function rtrim(string $string, string $characters = " \n\r\t\v\0"): string {} +function rtrim(string $string, string $characters = " \f\n\r\t\v\0"): string {} /** @alias rtrim */ -function chop(string $string, string $characters = " \n\r\t\v\0"): string {} +function chop(string $string, string $characters = " \f\n\r\t\v\0"): string {} /** @compile-time-eval */ -function ltrim(string $string, string $characters = " \n\r\t\v\0"): string {} +function ltrim(string $string, string $characters = " \f\n\r\t\v\0"): string {} /** * @compile-time-eval diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e467710f72f9..d0109fa27c96 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 8d1c2a735f412f8571675c6b025c3a418b68fb65 + * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) @@ -839,7 +839,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_trim, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, characters, IS_STRING, 0, "\" \\n\\r\\t\\v\\x00\"") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, characters, IS_STRING, 0, "\" \\f\\n\\r\\t\\v\\x00\"") ZEND_END_ARG_INFO() #define arginfo_rtrim arginfo_trim diff --git a/ext/standard/basic_functions_decl.h b/ext/standard/basic_functions_decl.h index 9e6fb0def447..139b47f2444d 100644 --- a/ext/standard/basic_functions_decl.h +++ b/ext/standard/basic_functions_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit basic_functions.stub.php instead. - * Stub hash: 8d1c2a735f412f8571675c6b025c3a418b68fb65 */ + * Stub hash: f5583557f058e4862750d1262296d7f59cb0eed0 */ -#ifndef ZEND_BASIC_FUNCTIONS_DECL_8d1c2a735f412f8571675c6b025c3a418b68fb65_H -#define ZEND_BASIC_FUNCTIONS_DECL_8d1c2a735f412f8571675c6b025c3a418b68fb65_H +#ifndef ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H +#define ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_HalfAwayFromZero = 1, @@ -15,4 +15,4 @@ typedef enum zend_enum_RoundingMode { ZEND_ENUM_RoundingMode_PositiveInfinity = 8, } zend_enum_RoundingMode; -#endif /* ZEND_BASIC_FUNCTIONS_DECL_8d1c2a735f412f8571675c6b025c3a418b68fb65_H */ +#endif /* ZEND_BASIC_FUNCTIONS_DECL_f5583557f058e4862750d1262296d7f59cb0eed0_H */ diff --git a/ext/standard/string.c b/ext/standard/string.c index d146b4534e27..7d609a032dd1 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -515,11 +515,16 @@ static inline zend_result php_charmask(const unsigned char *input, size_t len, c } /* }}} */ +static zend_always_inline bool php_is_whitespace(unsigned char c) +{ + return c <= ' ' && (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0'); +} + /* {{{ php_trim_int() * mode 1 : trim left * mode 2 : trim right * mode 3 : trim left and right - * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0') + * what indicates which chars are to be trimmed. NULL->default (' \f\t\n\r\v\0') */ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char *what, size_t what_len, int mode) { @@ -573,10 +578,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char } else { if (mode & 1) { while (start != end) { - unsigned char c = (unsigned char)*start; - - if (c <= ' ' && - (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) { + if (php_is_whitespace((unsigned char)*start)) { start++; } else { break; @@ -585,10 +587,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char } if (mode & 2) { while (start != end) { - unsigned char c = (unsigned char)*(end-1); - - if (c <= ' ' && - (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) { + if (php_is_whitespace((unsigned char)*(end-1))) { end--; } else { break; @@ -611,7 +610,7 @@ static zend_always_inline zend_string *php_trim_int(zend_string *str, const char * mode 1 : trim left * mode 2 : trim right * mode 3 : trim left and right - * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0') + * what indicates which chars are to be trimmed. NULL->default (' \f\t\n\r\v\0') */ PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len, int mode) { diff --git a/ext/standard/tests/strings/trim.phpt b/ext/standard/tests/strings/trim.phpt index fd0c26d7794a..9ce5e1dfff02 100644 --- a/ext/standard/tests/strings/trim.phpt +++ b/ext/standard/tests/strings/trim.phpt @@ -18,6 +18,9 @@ var_dump("ABC" === trim("ABC\x50\xC1\x60\x90","\x50..\xC1")); var_dump("ABC\x50\xC1" === trim("ABC\x50\xC1\x60\x90","\x51..\xC0")); var_dump("ABC\x50" === trim("ABC\x50\xC1\x60\x90","\x51..\xC1")); var_dump("ABC" === trim("ABC\x50\xC1\x60\x90","\x50..\xC1")); +var_dump("ABC" === trim("\fABC\f")); +var_dump("ABC" === ltrim("\fABC")); +var_dump("ABC" === rtrim("ABC\f")); ?> --EXPECT-- @@ -36,3 +39,6 @@ bool(true) bool(true) bool(true) bool(true) +bool(true) +bool(true) +bool(true) From 8bff64423377fb0c3c2ef279bdaf18e40e21a1c8 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 16:00:30 +0000 Subject: [PATCH 05/10] Zend: remove unused scope parameter of add_intersection_type() --- Zend/zend_compile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 23db72bb4fda..94956f990a0c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1417,7 +1417,7 @@ static zend_string *resolve_class_name(zend_string *name, const zend_class_entry } static zend_string *add_intersection_type(zend_string *str, - const zend_type_list *intersection_type_list, zend_class_entry *scope, + const zend_type_list *intersection_type_list, bool is_bracketed) { const zend_type *single_type; @@ -1448,13 +1448,13 @@ zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry /* Pure intersection type */ if (ZEND_TYPE_IS_INTERSECTION(type)) { ZEND_ASSERT(!ZEND_TYPE_IS_UNION(type)); - str = add_intersection_type(str, ZEND_TYPE_LIST(type), scope, /* is_bracketed */ false); + str = add_intersection_type(str, ZEND_TYPE_LIST(type), /* is_bracketed */ false); } else if (ZEND_TYPE_HAS_LIST(type)) { /* A union type might not be a list */ const zend_type *list_type; ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) { if (ZEND_TYPE_IS_INTERSECTION(*list_type)) { - str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), scope, /* is_bracketed */ true); + str = add_intersection_type(str, ZEND_TYPE_LIST(*list_type), /* is_bracketed */ true); continue; } ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); From 6880a6c49d8a4eb6b464a07b0addf2778b3d39b2 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 16:00:56 +0000 Subject: [PATCH 06/10] Zend: mark scope parameter of zend_type_to_string_resolved() const And propagate const qualifier to use sites of this function. --- Zend/zend_compile.c | 2 +- Zend/zend_compile.h | 2 +- Zend/zend_inheritance.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 94956f990a0c..3147fda23e9f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1442,7 +1442,7 @@ static zend_string *add_intersection_type(zend_string *str, return str; } -zend_string *zend_type_to_string_resolved(const zend_type type, zend_class_entry *scope) { +zend_string *zend_type_to_string_resolved(const zend_type type, const zend_class_entry *scope) { zend_string *str = NULL; /* Pure intersection type */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0b38084a107c..5414467f3f87 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1034,7 +1034,7 @@ int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem); void zend_assert_valid_class_name(const zend_string *const_name, const char *type); -zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope); +zend_string *zend_type_to_string_resolved(zend_type type, const zend_class_entry *scope); ZEND_API zend_string *zend_type_to_string(zend_type type); /* class fetches */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 9b3b6312cf25..e623e1e7aba3 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -60,8 +60,8 @@ static void add_property_hook_obligation( zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func); static void ZEND_COLD emit_incompatible_method_error( - const zend_function *child, zend_class_entry *child_scope, - const zend_function *parent, zend_class_entry *parent_scope, + const zend_function *child, const zend_class_entry *child_scope, + const zend_function *parent, const zend_class_entry *parent_scope, inheritance_status status); static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent); @@ -897,7 +897,7 @@ static inheritance_status zend_do_perform_implementation_check( /* }}} */ static ZEND_COLD void zend_append_type_hint( - smart_str *str, zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */ + smart_str *str, const zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */ { if (ZEND_TYPE_IS_SET(arg_info->type)) { zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope); @@ -911,7 +911,7 @@ static ZEND_COLD void zend_append_type_hint( /* }}} */ static ZEND_COLD zend_string *zend_get_function_declaration( - const zend_function *fptr, zend_class_entry *scope) /* {{{ */ + const zend_function *fptr, const zend_class_entry *scope) /* {{{ */ { smart_str str = {0}; @@ -1054,8 +1054,8 @@ static zend_always_inline uint32_t func_lineno(const zend_function *fn) { } static void ZEND_COLD emit_incompatible_method_error( - const zend_function *child, zend_class_entry *child_scope, - const zend_function *parent, zend_class_entry *parent_scope, + const zend_function *child, const zend_class_entry *child_scope, + const zend_function *parent, const zend_class_entry *parent_scope, inheritance_status status) { zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope); zend_string *child_prototype = zend_get_function_declaration(child, child_scope); From 2b20627cbce44ca45f3230498d3ac17cb5831a0d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 16:09:32 +0000 Subject: [PATCH 07/10] Zend: mark zend_perform_covariant_type_check() as static This function is not defined in any headers --- Zend/zend_inheritance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index e623e1e7aba3..3313b0755861 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -671,7 +671,7 @@ static inheritance_status zend_is_intersection_subtype_of_type( return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR; } -ZEND_API inheritance_status zend_perform_covariant_type_check( +static inheritance_status zend_perform_covariant_type_check( zend_class_entry *fe_scope, const zend_type fe_type, zend_class_entry *proto_scope, const zend_type proto_type) { From 032e5f6774694bfd64311387a205a7aec39c4fcb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 16:14:06 +0000 Subject: [PATCH 08/10] Zend: mark arg_info parameters of zend_do_perform_arg_type_hint_check() const --- Zend/zend_inheritance.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 3313b0755861..93186f439d23 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -763,8 +763,8 @@ static inheritance_status zend_perform_covariant_type_check( } static inheritance_status zend_do_perform_arg_type_hint_check( - zend_class_entry *fe_scope, zend_arg_info *fe_arg_info, - zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */ + zend_class_entry *fe_scope, const zend_arg_info *fe_arg_info, + zend_class_entry *proto_scope, const zend_arg_info *proto_arg_info) /* {{{ */ { if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) { /* Child with no type or mixed type is always compatible */ From 1096ea149ae921956db31f694960e996c78888b5 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 16:24:51 +0000 Subject: [PATCH 09/10] Zend: mark variable as const --- Zend/zend_inheritance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 93186f439d23..b5fc262ec1ea 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -320,7 +320,7 @@ static bool unlinked_instanceof(const zend_class_entry *ce1, const zend_class_en } if (ce1->parent) { - zend_class_entry *parent_ce; + const zend_class_entry *parent_ce; if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) { parent_ce = ce1->parent; } else { From f93b17076a25e2a06af50a6d177ae4badc5e44c3 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Mon, 9 Mar 2026 21:57:50 +0000 Subject: [PATCH 10/10] Zend: inherit interfaces early (#18622) The primary motivation for this is that this is required for my abstract generic types proof of concept, as the resolving of bound types needs to happen early to properly track the types. However, there doesn't seem to be a good reason for delaying the inheritance of interfaces. This approach might even allow us to drop the `iface` parameter of the `interface_gets_implemented()` handler as the interface name is always known. --- .../enum/no-class-implements-backed-enum.phpt | 2 +- ...y_interfaces_error_via_indirect_interface.phpt | 15 +++++++++++++++ Zend/zend_inheritance.c | 7 ++++--- 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/inheritance/enum_only_interfaces_error_via_indirect_interface.phpt diff --git a/Zend/tests/enum/no-class-implements-backed-enum.phpt b/Zend/tests/enum/no-class-implements-backed-enum.phpt index f6f37818da5a..f8d4fd13a423 100644 --- a/Zend/tests/enum/no-class-implements-backed-enum.phpt +++ b/Zend/tests/enum/no-class-implements-backed-enum.phpt @@ -7,4 +7,4 @@ class Foo implements BackedEnum {} ?> --EXPECTF-- -Fatal error: Non-enum class Foo cannot implement interface BackedEnum in %s on line %d +Fatal error: Non-enum class Foo cannot implement interface UnitEnum in %s on line %d diff --git a/Zend/tests/inheritance/enum_only_interfaces_error_via_indirect_interface.phpt b/Zend/tests/inheritance/enum_only_interfaces_error_via_indirect_interface.phpt new file mode 100644 index 000000000000..66a921532055 --- /dev/null +++ b/Zend/tests/inheritance/enum_only_interfaces_error_via_indirect_interface.phpt @@ -0,0 +1,15 @@ +--TEST-- +Interface that is extended from Enum only interface shouldn't be implementable by non-enum class +--FILE-- + +--EXPECTF-- +Fatal error: Non-enum class C cannot implement interface UnitEnum in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index b5fc262ec1ea..ba13a3233ed2 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2168,6 +2168,10 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry * zend_class_constant *c; uint32_t flags = ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY; + if (iface->num_interfaces) { + zend_do_inherit_interfaces(ce, iface); + } + if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) { /* We are not setting the prototype of overridden interface methods because of abstract * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */ @@ -2199,9 +2203,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry * } ZEND_HASH_FOREACH_END(); do_implement_interface(ce, iface); - if (iface->num_interfaces) { - zend_do_inherit_interfaces(ce, iface); - } } /* }}} */