From f138ce29df156ea250a8faadf6f62feeb0107135 Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 17 Aug 2026 14:50:32 +0500 Subject: [PATCH 1/4] session: fix create_sid()/validateId() check depending on interface order --- ext/session/session.c | 17 +++++++++++++++-- ext/session/tests/gh23328.phpt | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 ext/session/tests/gh23328.phpt diff --git a/ext/session/session.c b/ext/session/session.c index a6e698d4c0aa..18bcc44cb0a9 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2935,13 +2935,26 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->random_seeded = false; } +/* Sibling interfaces are not merged into the function table yet when this runs */ +static bool session_class_implements_interface(const zend_class_entry *class, const zend_class_entry *iface) +{ + for (uint32_t i = 0; i < class->num_interfaces; i++) { + if (instanceof_function(class->interfaces[i], iface)) { + return true; + } + } + return false; +} + static int session_handler_interface_gets_implemented(zend_class_entry *self, zend_class_entry *class) { - if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid"))) { + if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid")) + && !session_class_implements_interface(class, php_session_id_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); } - if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid"))) { + if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid")) + && !session_class_implements_interface(class, php_session_update_timestamp_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); diff --git a/ext/session/tests/gh23328.phpt b/ext/session/tests/gh23328.phpt new file mode 100644 index 000000000000..93e490993316 --- /dev/null +++ b/ext/session/tests/gh23328.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-23328: SessionHandlerInterface create_sid()/validateId() warning depends on the order interfaces are listed in +--EXTENSIONS-- +session +--FILE-- + +--EXPECTF-- +Warning: Class HandlerAlone implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class HandlerAlone implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d +Done From 698f2f4aac296538d408b3b930dff025046388ef Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 17 Aug 2026 15:54:16 +0500 Subject: [PATCH 2/4] session: check the interface methods instead of the interface names --- ext/session/session.c | 13 +++++++------ ext/session/tests/gh23328.phpt | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index 18bcc44cb0a9..d2c794a747b5 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2935,11 +2935,12 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->random_seeded = false; } -/* Sibling interfaces are not merged into the function table yet when this runs */ -static bool session_class_implements_interface(const zend_class_entry *class, const zend_class_entry *iface) +/* The interfaces listed after SessionHandlerInterface have not had their abstract methods + * inherited into the function table yet, so look them up in the interface list as well. */ +static bool session_interfaces_declare_method(const zend_class_entry *ce, const char *name, size_t name_len) { - for (uint32_t i = 0; i < class->num_interfaces; i++) { - if (instanceof_function(class->interfaces[i], iface)) { + for (uint32_t i = 0; i < ce->num_interfaces; i++) { + if (zend_hash_str_exists(&ce->interfaces[i]->function_table, name, name_len)) { return true; } } @@ -2948,13 +2949,13 @@ static bool session_class_implements_interface(const zend_class_entry *class, co static int session_handler_interface_gets_implemented(zend_class_entry *self, zend_class_entry *class) { if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid")) - && !session_class_implements_interface(class, php_session_id_iface_entry)) { + && !session_interfaces_declare_method(class, ZEND_STRL("create_sid"))) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); } if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid")) - && !session_class_implements_interface(class, php_session_update_timestamp_iface_entry)) { + && !session_interfaces_declare_method(class, ZEND_STRL("validateid"))) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); diff --git a/ext/session/tests/gh23328.phpt b/ext/session/tests/gh23328.phpt index 93e490993316..261d8e7e0350 100644 --- a/ext/session/tests/gh23328.phpt +++ b/ext/session/tests/gh23328.phpt @@ -1,5 +1,5 @@ --TEST-- -GH-23328: SessionHandlerInterface create_sid()/validateId() warning depends on the order interfaces are listed in +GH-23328: SessionHandlerInterface create_sid()/validateId() warning depends on interface order --EXTENSIONS-- session --FILE-- @@ -9,14 +9,27 @@ abstract class HandlerFirst implements SessionHandlerInterface, SessionIdInterfa abstract class HandlerLast implements SessionIdInterface, SessionUpdateTimestampHandlerInterface, SessionHandlerInterface {} interface CombinedInterface extends SessionIdInterface, SessionUpdateTimestampHandlerInterface {} -abstract class HandlerCombined implements SessionHandlerInterface, CombinedInterface {} +abstract class CombinedFirst implements CombinedInterface, SessionHandlerInterface {} +abstract class CombinedLast implements SessionHandlerInterface, CombinedInterface {} -abstract class HandlerAlone implements SessionHandlerInterface {} +interface OwnMethods { + public function create_sid(): string; + public function validateId(string $id): bool; +} +abstract class OwnMethodsLast implements SessionHandlerInterface, OwnMethods {} + +abstract class MissingBoth implements SessionHandlerInterface {} +abstract class MissingValidateId implements SessionHandlerInterface, SessionIdInterface {} +abstract class MissingCreateSid implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {} echo "Done\n"; ?> --EXPECTF-- -Warning: Class HandlerAlone implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d +Warning: Class MissingBoth implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class MissingBoth implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d + +Warning: Class MissingValidateId implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d -Warning: Class HandlerAlone implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in %s on line %d +Warning: Class MissingCreateSid implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in %s on line %d Done From a783cff8842feeb4abeff1ab427dfed6f492a384 Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 17 Aug 2026 16:51:49 +0500 Subject: [PATCH 3/4] session: check the interface entries instead of the method names --- ext/session/tests/{ => user_session_module}/gh23328.phpt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ext/session/tests/{ => user_session_module}/gh23328.phpt (100%) diff --git a/ext/session/tests/gh23328.phpt b/ext/session/tests/user_session_module/gh23328.phpt similarity index 100% rename from ext/session/tests/gh23328.phpt rename to ext/session/tests/user_session_module/gh23328.phpt From 0c963e49c8e256dc444cea7ec2c5dbec9f1bc59a Mon Sep 17 00:00:00 2001 From: Lazizbek Ergashev Date: Mon, 17 Aug 2026 17:51:45 +0500 Subject: [PATCH 4/4] session: use the session interfaces for the missing method check --- ext/session/session.c | 12 ++++++------ ext/session/tests/user_session_module/gh23328.phpt | 7 ++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index d2c794a747b5..e745a628767f 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2935,12 +2935,12 @@ static PHP_GINIT_FUNCTION(ps) ps_globals->random_seeded = false; } -/* The interfaces listed after SessionHandlerInterface have not had their abstract methods - * inherited into the function table yet, so look them up in the interface list as well. */ -static bool session_interfaces_declare_method(const zend_class_entry *ce, const char *name, size_t name_len) +/* Interfaces extending the given one are not flattened into ce->interfaces before they are + * themselves processed, so every entry has to be checked with instanceof. */ +static bool session_interfaces_include(const zend_class_entry *ce, const zend_class_entry *iface) { for (uint32_t i = 0; i < ce->num_interfaces; i++) { - if (zend_hash_str_exists(&ce->interfaces[i]->function_table, name, name_len)) { + if (instanceof_function(ce->interfaces[i], iface)) { return true; } } @@ -2949,13 +2949,13 @@ static bool session_interfaces_declare_method(const zend_class_entry *ce, const static int session_handler_interface_gets_implemented(zend_class_entry *self, zend_class_entry *class) { if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("create_sid")) - && !session_interfaces_declare_method(class, ZEND_STRL("create_sid"))) { + && !session_interfaces_include(class, php_session_id_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); } if (!zend_hash_str_exists(&class->function_table, ZEND_STRL("validateid")) - && !session_interfaces_declare_method(class, ZEND_STRL("validateid"))) { + && !session_interfaces_include(class, php_session_update_timestamp_iface_entry)) { zend_error(E_WARNING, "Class %s implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0", ZSTR_VAL(class->name)); diff --git a/ext/session/tests/user_session_module/gh23328.phpt b/ext/session/tests/user_session_module/gh23328.phpt index 261d8e7e0350..c23ccb1de389 100644 --- a/ext/session/tests/user_session_module/gh23328.phpt +++ b/ext/session/tests/user_session_module/gh23328.phpt @@ -12,11 +12,8 @@ interface CombinedInterface extends SessionIdInterface, SessionUpdateTimestampHa abstract class CombinedFirst implements CombinedInterface, SessionHandlerInterface {} abstract class CombinedLast implements SessionHandlerInterface, CombinedInterface {} -interface OwnMethods { - public function create_sid(): string; - public function validateId(string $id): bool; -} -abstract class OwnMethodsLast implements SessionHandlerInterface, OwnMethods {} +interface NestedInterface extends CombinedInterface {} +abstract class NestedLast implements SessionHandlerInterface, NestedInterface {} abstract class MissingBoth implements SessionHandlerInterface {} abstract class MissingValidateId implements SessionHandlerInterface, SessionIdInterface {}