[php-src] Issue #23328: SessionHandlerInterface create_sid()/validateId() warning depends on the order interfaces are listed in

[email protected] (nicolas-grekas)
Newsgroups php.bugs
Message-ID <zmKpgYEaMsLkOvctjF9fO3Gnw6nTEhapVWtAuK16hkU@main.internal.php.net>
Issue: https://github.com/php/php-src/issues/23328
Author: nicolas-grekas

### Description

The `create_sid()`/`validateId()` check added in 6901c87aeabf28cbb08dadc2ac64d1dabfdfdd3c depends on the order the interfaces are listed in, so a class that does implement `SessionIdInterface` and `SessionUpdateTimestampHandlerInterface` can still be reported as missing their methods.

The following code:

```php
<?php
abstract class A implements SessionHandlerInterface, SessionIdInterface, SessionUpdateTimestampHandlerInterface {}
abstract class B implements SessionIdInterface, SessionUpdateTimestampHandlerInterface, SessionHandlerInterface {}
```

Resulted in this output:
```
Warning: Class A implementing SessionHandlerInterface is missing the create_sid() method which will be required in PHP 9.0 in /tmp/iface-order.php on line 2

Warning: Class A implementing SessionHandlerInterface is missing the validateId() method which will be required in PHP 9.0 in /tmp/iface-order.php on line 2
```

But I expected this output instead:
```
```

`A` and `B` differ only in the order of the `implements` list, and both declare `create_sid()` and `validateId()` through the interfaces they implement.

`session_handler_interface_gets_implemented()` is registered as the `interface_gets_implemented` handler of `SessionHandlerInterface`, so it runs while that interface is being attached to the class. At that point the sibling interfaces have not been linked yet, so `class->function_table` only holds the methods the class declares itself:

```c
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"))) {
```

Listing `SessionIdInterface` before `SessionHandlerInterface` makes the abstract method present in time and the warning disappears, which is why `B` is silent.

Declaring the methods on the class itself also silences it, so this only affects classes that rely on the interfaces to declare them — abstract classes and interfaces meant to be implemented further down, where declaring the methods again would be redundant.

### PHP Version

```plain
PHP 8.6.0-dev (cli) (built: Aug 16 2026 17:43:53) (NTS DEBUG)
Copyright © The PHP Group and Contributors
Zend Engine v4.6.0-dev, Copyright © Zend by Perforce
    with Zend OPcache v8.6.0-dev, Copyright ©, by Zend by Perforce
```

Built from 9f32f90ad35.

### Operating System

Ubuntu 24.04.4 LTS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.