Questions about event ->add() callback

Issue #71 on hold
liyi created an issue

$base = new EventBase();

$socket = stream_socket_server('tcp://0.0.0.0:9999', $errCode, $errMsg, \STREAM_SERVER_BIND |
    \STREAM_SERVER_LISTEN, $content);
// first event callback success
$event = new Event($base, $socket, Event::READ|Event::PERSIST, function ($socket, $fd, $arg) {
    $newSocket = stream_socket_accept($socket, 0, $remoteAddress);

    // this Event callback not running
    $event = new Event($arg[0], $newSocket, Event::READ|Event::PERSIST, function ($socket) {
        $buff = fread($socket, 65535);
    });

    $event->add();
}, [&$base]);

$event->add();

$base->loop();

In the execution of the first closure, continue to add the second event, the second event callback is not executed,If the second event is encapsulated into a class, it can be executed normally

The following code can be written normally

class TcpConn
{
    /**
     * @var resource
     */
    public $socket;

    public function __construct($socket)
    {
        $this->socket = $socket;

        Master::$globalEvent->add($this->socket, [$this, 'read'], 'stream_socket_accept');
    }

    public function read($socket)
    {
        $buff = fread($socket, 65536);

        echo "客户端请求来了~\n";

        echo $buff . "\n";

        if (is_resource($socket)) {
            fwrite($socket, "HTTP/1.1 200 OK\r\nAccept: application/json, text/plain, */*\r\nConnection: keep-alive\r\nContent-Length: 6\r\n\r\nhello~");
        }
    }
}


Master::$globalEvent = new EventLoop();

Master::$globalEvent->add($mainSocket, function ($sock) {
    $newSocket = stream_socket_accept($sock, 0, $remoteAddress);

    \stream_set_blocking($newSocket, 0);
    // Compatible with hhvm
    if (\function_exists('stream_set_read_buffer')) {
        \stream_set_read_buffer($newSocket, 0);
    }

    echo 'remote address : ' . $remoteAddress . PHP_EOL;

    new TcpConn($newSocket);

}, 'stream_socket_server');

Master::$globalEvent->loop();

echo "wait process exit~ pid = " . posix_getpid();

Comments (3)

  1. Ruslan Osmanov repo owner

    The issue with the second callback is that the local $event variable is not preserved. When $event goes out of the scope of the closure, it gets destroyed. As a result, the inner $event is never triggered.

    You can avoid this by maintaining a reference to the event object somewhere outside of the inner scope, until it is no longer needed.

    I hope this makes it a little bit more clear for you.

    (I understand, that in an ideal world the PECL extension would magically handle this case :-))

  2. Log in to comment