socketsevent-listenerfile-descriptorlibeventphp-8

PHP8/EventListener - Getting Socket instance from file descriptor


PHP8 has introduced Socket class that replaces old socket resource. Now all socket functions works with the instance of this class.

The 2nd argument of EventListener's constructor (https://www.php.net/manual/en/class.eventlistener.php) is callback function. It is called when new connection event arises. There is signature of this callback function: https://www.php.net/manual/en/eventlistener.setcallback.php . It receives file descriptor as the 2nd argument. File descriptor is numeric value, but I need instance of Socket class, because next I will pass it to constructor of EventBufferEvent.

Please advice how can I acquire instance of Socket for this file descriptor?


Solution that doesn't work:

I tried to find address and port that are bound to the file descriptor, then create new socket and bind it to this address and port. But that creates new socket with new file descriptor, not related to connection received in callback of event listener.

I'm stuck on finding any useful documentation or code samples for my problem while migrating my event-based socket server to php8.


Solution

  • The short answer is: you can pass the numeric file descriptor as the 2nd argument to EventBufferEvent::__construct.


    https://www.php.net/manual/en/eventlistener.setcallback.php . It receives file descriptor as the 2nd argument. File descriptor is numeric value, but I need instance of Socket class, because next I will pass it to constructor of EventBufferEvent.

    There is an inaccuracy in the the documentation of EventBufferEvent::__construct:

    socket

    May be created as a stream(not necessarily by means of sockets extension)

    It is slightly misleading because the second argument is actually as flexible as most of the Event functions that accept an "fd" or a "stream". Event tries to get numeric file descriptor from the argument, and if it is already a numeric value, it uses it.

    See how the "Echo server" example creates an instance of EventBufferEvent for every connection:

    class MyListenerConnection {
        public function __construct($base, $fd) {
            $this->base = $base;
            $this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE);
    
    // ...
    
    $this->conn[] = new MyListenerConnection($base, $fd);