PHP7 and inherited class
Hello, found a bug with PHP 7.0, and EventBufferEvent object created in inherited class. Here is the code with Redis connection example:
class Generic
{
public $base = NULL;
public function start()
{
$this->base = new \EventBase();
$this->onStart();
// move onStart code here to fix //
$this->base->dispatch();
}
}
class Worker extends Generic
{
protected function onStart()
{
$redis = new \EventBufferEvent($this->base);
$redis->setCallbacks(
function ($bev, $events, $unused=null)
{
echo "onRead\n";
while (($line = $bev->input->readLine(\EventBuffer::EOL_ANY)) !== null) {
echo $line."\r\n";
}
},
null,
function ($bev, $events, $unused=null)
{
echo "onEvent\n";
if ($events & (\EventBufferEvent::EOF | \EventBufferEvent::ERROR)) {
$bev->free();
$bev = NULL;
} elseif ($events & \EventBufferEvent::CONNECTED) {
echo "redis: connected\n";
$command = 'PSUBSCRIBE';
$args = ['*'];
$data = '*' . (count($args) + 1) . "\r\n$" . strlen($command) . "\r\n" . $command . "\r\n";
foreach ($args as $arg) {
$data .= '$' . strlen($arg) . "\r\n" . $arg . "\r\n";
}
$bev->write($data);
}
}
);
if (!$redis->connect('127.0.0.1:6379')) {
trigger_error("conn: Failed to connect to socket", E_USER_ERROR);
} else {
echo("socket to redis connected\n");
}
if (!$redis->enable(\Event::READ|\Event::WRITE|\Event::TIMEOUT|\Event::PERSIST)) {
trigger_error("conn: Failed to enable socket", E_USER_ERROR);
} else {
echo("socket to redis event enabled\n");
}
$redis->setWatermark(\Event::READ, 16, 0xFFFF);
$redis->setTimeouts(0, 0);
}
}
$worker = new Worker();
$worker->start();
note when the code moved from onStart() to start(), the problem is fixed.
Comments (4)
-
-
Indeed, making it into property fixes the problem. Note that in PHP5.6 it worked OK. Thank you!
-
Ah ok, that's interesting. I'm only familiar with event on php >7.0. Glad you sorted it.
I think it makes more sense that you should have to maintain a reference to your EventBufferEvent object. Seems a bit ambiguous how it would work otherwise, as the object would become hidden away in a scope of its own with no way to further interact with it - in effect it would be leaked, and we don't want that.
-
repo owner - changed status to invalid
@cidious, @fredfredfred is right. You should keep a reference to the
EventBufferEvent
($redis
) object. Otherwise, it will be destroyed when it goes out of scope as any other variable in PHP. In particular,EventBufferEvent
's destructor is called between$this->onStart()
and$this->base->dispatch()
. - Log in to comment
It could be that you need to make $redis into a class property. As things stand it goes out of scope as soon as onStart returns.