From 427853c16a6425d86b89f40067752864d488afa2 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 13 Jun 2018 12:27:13 +0200 Subject: [PATCH 1/4] Found zeh bug: `spl_objet_hash()` was used instead of `spl_object_hash()` --- src/Timer/Timers.php | 2 +- tests/Timer/TimersTest.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Timer/Timers.php b/src/Timer/Timers.php index 7944b4c1..fa4bd628 100644 --- a/src/Timer/Timers.php +++ b/src/Timer/Timers.php @@ -21,7 +21,7 @@ final class Timers public function updateTime() { - return $this->time = microtime(true); + return $this->time = \microtime(true); } public function getTime() diff --git a/tests/Timer/TimersTest.php b/tests/Timer/TimersTest.php index b279478c..d4e6987d 100644 --- a/tests/Timer/TimersTest.php +++ b/tests/Timer/TimersTest.php @@ -2,6 +2,7 @@ namespace React\Tests\EventLoop\Timer; +use React\EventLoop\TimerInterface; use React\Tests\EventLoop\TestCase; use React\EventLoop\Timer\Timer; use React\EventLoop\Timer\Timers; @@ -24,4 +25,19 @@ public function testBlockedTimer() $this->assertTrue(true); } + + public function testContains() + { + $timers = new Timers(); + + /** @var TimerInterface $timer1 */ + $timer1 = $this->createMock('React\EventLoop\TimerInterface'); + /** @var TimerInterface $timer2 */ + $timer2 = $this->createMock('React\EventLoop\TimerInterface'); + + $timers->add($timer1); + + self::assertTrue($timers->contains($timer1)); + self::assertFalse($timers->contains($timer2)); + } } From 75bead60043668902e39bbfc6bd5135161a18f6c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 13 Jun 2018 12:27:35 +0200 Subject: [PATCH 2/4] Importing global functions - micro-optimisation, but relevant for this high-throughput component --- src/ExtEvLoop.php | 6 ++-- src/ExtEventLoop.php | 8 ++--- src/ExtLibevLoop.php | 10 +++--- src/ExtLibeventLoop.php | 62 ++++++++++++++++++------------------ src/Factory.php | 8 ++--- src/SignalsHandler.php | 2 +- src/StreamSelectLoop.php | 10 +++--- src/Tick/FutureTickQueue.php | 2 +- src/Timer/Timers.php | 18 +++++------ 9 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/ExtEvLoop.php b/src/ExtEvLoop.php index 4347263c..fedd5884 100644 --- a/src/ExtEvLoop.php +++ b/src/ExtEvLoop.php @@ -92,7 +92,7 @@ public function addReadStream($stream, $listener) private function getStreamListenerClosure($stream, $listener) { return function () use ($stream, $listener) { - call_user_func($listener, $stream); + \call_user_func($listener, $stream); }; } @@ -140,7 +140,7 @@ public function addTimer($interval, $callback) $that = $this; $timers = $this->timers; $callback = function () use ($timer, $timers, $that) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); if ($timers->contains($timer)) { $that->cancelTimer($timer); @@ -158,7 +158,7 @@ public function addPeriodicTimer($interval, $callback) $timer = new Timer($interval, $callback, true); $callback = function () use ($timer) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); }; $event = $this->loop->timer($interval, $interval, $callback); diff --git a/src/ExtEventLoop.php b/src/ExtEventLoop.php index 622dd472..a6153505 100644 --- a/src/ExtEventLoop.php +++ b/src/ExtEventLoop.php @@ -39,7 +39,7 @@ final class ExtEventLoop implements LoopInterface public function __construct() { - if (!class_exists('EventBase', false)) { + if (!\class_exists('EventBase', false)) { throw new BadMethodCallException('Cannot create ExtEventLoop, ext-event extension missing'); } @@ -225,7 +225,7 @@ private function createTimerCallback() { $timers = $this->timerEvents; $this->timerCallback = function ($_, $__, $timer) use ($timers) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); if (!$timer->isPeriodic() && $timers->contains($timer)) { $this->cancelTimer($timer); @@ -248,11 +248,11 @@ private function createStreamCallback() $key = (int) $stream; if (Event::READ === (Event::READ & $flags) && isset($read[$key])) { - call_user_func($read[$key], $stream); + \call_user_func($read[$key], $stream); } if (Event::WRITE === (Event::WRITE & $flags) && isset($write[$key])) { - call_user_func($write[$key], $stream); + \call_user_func($write[$key], $stream); } }; } diff --git a/src/ExtLibevLoop.php b/src/ExtLibevLoop.php index d3b0df81..193c6c0d 100644 --- a/src/ExtLibevLoop.php +++ b/src/ExtLibevLoop.php @@ -37,7 +37,7 @@ final class ExtLibevLoop implements LoopInterface public function __construct() { - if (!class_exists('libev\EventLoop', false)) { + if (!\class_exists('libev\EventLoop', false)) { throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing'); } @@ -54,7 +54,7 @@ public function addReadStream($stream, $listener) } $callback = function () use ($stream, $listener) { - call_user_func($listener, $stream); + \call_user_func($listener, $stream); }; $event = new IOEvent($callback, $stream, IOEvent::READ); @@ -70,7 +70,7 @@ public function addWriteStream($stream, $listener) } $callback = function () use ($stream, $listener) { - call_user_func($listener, $stream); + \call_user_func($listener, $stream); }; $event = new IOEvent($callback, $stream, IOEvent::WRITE); @@ -108,7 +108,7 @@ public function addTimer($interval, $callback) $that = $this; $timers = $this->timerEvents; $callback = function () use ($timer, $timers, $that) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); if ($timers->contains($timer)) { $that->cancelTimer($timer); @@ -127,7 +127,7 @@ public function addPeriodicTimer($interval, $callback) $timer = new Timer($interval, $callback, true); $callback = function () use ($timer) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); }; $event = new TimerEvent($callback, $interval, $interval); diff --git a/src/ExtLibeventLoop.php b/src/ExtLibeventLoop.php index 427f8db0..ddd66569 100644 --- a/src/ExtLibeventLoop.php +++ b/src/ExtLibeventLoop.php @@ -53,11 +53,11 @@ final class ExtLibeventLoop implements LoopInterface public function __construct() { - if (!function_exists('event_base_new')) { + if (!\function_exists('event_base_new')) { throw new BadMethodCallException('Cannot create ExtLibeventLoop, ext-libevent extension missing'); } - $this->eventBase = event_base_new(); + $this->eventBase = \event_base_new(); $this->futureTickQueue = new FutureTickQueue(); $this->timerEvents = new SplObjectStorage(); $this->signals = new SignalsHandler(); @@ -73,10 +73,10 @@ public function addReadStream($stream, $listener) return; } - $event = event_new(); - event_set($event, $stream, EV_PERSIST | EV_READ, $this->streamCallback); - event_base_set($event, $this->eventBase); - event_add($event); + $event = \event_new(); + \event_set($event, $stream, EV_PERSIST | EV_READ, $this->streamCallback); + \event_base_set($event, $this->eventBase); + \event_add($event); $this->readEvents[$key] = $event; $this->readListeners[$key] = $listener; @@ -89,10 +89,10 @@ public function addWriteStream($stream, $listener) return; } - $event = event_new(); - event_set($event, $stream, EV_PERSIST | EV_WRITE, $this->streamCallback); - event_base_set($event, $this->eventBase); - event_add($event); + $event = \event_new(); + \event_set($event, $stream, EV_PERSIST | EV_WRITE, $this->streamCallback); + \event_base_set($event, $this->eventBase); + \event_add($event); $this->writeEvents[$key] = $event; $this->writeListeners[$key] = $listener; @@ -104,8 +104,8 @@ public function removeReadStream($stream) if (isset($this->readListeners[$key])) { $event = $this->readEvents[$key]; - event_del($event); - event_free($event); + \event_del($event); + \event_free($event); unset( $this->readEvents[$key], @@ -120,8 +120,8 @@ public function removeWriteStream($stream) if (isset($this->writeListeners[$key])) { $event = $this->writeEvents[$key]; - event_del($event); - event_free($event); + \event_del($event); + \event_free($event); unset( $this->writeEvents[$key], @@ -152,8 +152,8 @@ public function cancelTimer(TimerInterface $timer) { if ($this->timerEvents->contains($timer)) { $event = $this->timerEvents[$timer]; - event_del($event); - event_free($event); + \event_del($event); + \event_free($event); $this->timerEvents->detach($timer); } @@ -169,10 +169,10 @@ public function addSignal($signal, $listener) $this->signals->add($signal, $listener); if (!isset($this->signalEvents[$signal])) { - $this->signalEvents[$signal] = event_new(); - event_set($this->signalEvents[$signal], $signal, EV_PERSIST | EV_SIGNAL, array($this->signals, 'call')); - event_base_set($this->signalEvents[$signal], $this->eventBase); - event_add($this->signalEvents[$signal]); + $this->signalEvents[$signal] = \event_new(); + \event_set($this->signalEvents[$signal], $signal, EV_PERSIST | EV_SIGNAL, array($this->signals, 'call')); + \event_base_set($this->signalEvents[$signal], $this->eventBase); + \event_add($this->signalEvents[$signal]); } } @@ -181,8 +181,8 @@ public function removeSignal($signal, $listener) $this->signals->remove($signal, $listener); if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) { - event_del($this->signalEvents[$signal]); - event_free($this->signalEvents[$signal]); + \event_del($this->signalEvents[$signal]); + \event_free($this->signalEvents[$signal]); unset($this->signalEvents[$signal]); } } @@ -201,7 +201,7 @@ public function run() break; } - event_base_loop($this->eventBase, $flags); + \event_base_loop($this->eventBase, $flags); } } @@ -217,11 +217,11 @@ public function stop() */ private function scheduleTimer(TimerInterface $timer) { - $this->timerEvents[$timer] = $event = event_timer_new(); + $this->timerEvents[$timer] = $event = \event_timer_new(); - event_timer_set($event, $this->timerCallback, $timer); - event_base_set($event, $this->eventBase); - event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND); + \event_timer_set($event, $this->timerCallback, $timer); + \event_base_set($event, $this->eventBase); + \event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND); } /** @@ -236,7 +236,7 @@ private function createTimerCallback() $that = $this; $timers = $this->timerEvents; $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) { - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); // Timer already cancelled ... if (!$timers->contains($timer)) { @@ -245,7 +245,7 @@ private function createTimerCallback() // Reschedule periodic timers ... if ($timer->isPeriodic()) { - event_add( + \event_add( $timers[$timer], $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND ); @@ -272,11 +272,11 @@ private function createStreamCallback() $key = (int) $stream; if (EV_READ === (EV_READ & $flags) && isset($read[$key])) { - call_user_func($read[$key], $stream); + \call_user_func($read[$key], $stream); } if (EV_WRITE === (EV_WRITE & $flags) && isset($write[$key])) { - call_user_func($write[$key], $stream); + \call_user_func($write[$key], $stream); } }; } diff --git a/src/Factory.php b/src/Factory.php index b46fc074..48801466 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -24,13 +24,13 @@ final class Factory public static function create() { // @codeCoverageIgnoreStart - if (class_exists('libev\EventLoop', false)) { + if (\class_exists('libev\EventLoop', false)) { return new ExtLibevLoop(); - } elseif (class_exists('EvLoop', false)) { + } elseif (\class_exists('EvLoop', false)) { return new ExtEvLoop(); - } elseif (class_exists('EventBase', false)) { + } elseif (\class_exists('EventBase', false)) { return new ExtEventLoop(); - } elseif (function_exists('event_base_new') && PHP_VERSION_ID < 70000) { + } elseif (\function_exists('event_base_new') && PHP_VERSION_ID < 70000) { // only use ext-libevent on PHP < 7 for now return new ExtLibeventLoop(); } diff --git a/src/SignalsHandler.php b/src/SignalsHandler.php index 523e1ca1..10d125df 100644 --- a/src/SignalsHandler.php +++ b/src/SignalsHandler.php @@ -15,7 +15,7 @@ public function add($signal, $listener) $this->signals[$signal] = array(); } - if (in_array($listener, $this->signals[$signal])) { + if (\in_array($listener, $this->signals[$signal])) { return; } diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index e82e9e47..7b822e01 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -68,7 +68,7 @@ public function __construct() { $this->futureTickQueue = new FutureTickQueue(); $this->timers = new Timers(); - $this->pcntl = extension_loaded('pcntl'); + $this->pcntl = \extension_loaded('pcntl'); $this->signals = new SignalsHandler(); } @@ -235,7 +235,7 @@ private function waitForStreamActivity($timeout) $key = (int) $stream; if (isset($this->readListeners[$key])) { - call_user_func($this->readListeners[$key], $stream); + \call_user_func($this->readListeners[$key], $stream); } } @@ -243,7 +243,7 @@ private function waitForStreamActivity($timeout) $key = (int) $stream; if (isset($this->writeListeners[$key])) { - call_user_func($this->writeListeners[$key], $stream); + \call_user_func($this->writeListeners[$key], $stream); } } } @@ -265,10 +265,10 @@ private function streamSelect(array &$read, array &$write, $timeout) $except = null; // suppress warnings that occur, when stream_select is interrupted by a signal - return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); + return @\stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); } - $timeout && usleep($timeout); + $timeout && \usleep($timeout); return 0; } diff --git a/src/Tick/FutureTickQueue.php b/src/Tick/FutureTickQueue.php index c79afc56..efabcbc5 100644 --- a/src/Tick/FutureTickQueue.php +++ b/src/Tick/FutureTickQueue.php @@ -42,7 +42,7 @@ public function tick() $count = $this->queue->count(); while ($count--) { - call_user_func( + \call_user_func( $this->queue->dequeue() ); } diff --git a/src/Timer/Timers.php b/src/Timer/Timers.php index fa4bd628..1d4ac9b7 100644 --- a/src/Timer/Timers.php +++ b/src/Timer/Timers.php @@ -31,20 +31,20 @@ public function getTime() public function add(TimerInterface $timer) { - $id = spl_object_hash($timer); + $id = \spl_object_hash($timer); $this->timers[$id] = $timer; - $this->schedule[$id] = $timer->getInterval() + microtime(true); + $this->schedule[$id] = $timer->getInterval() + \microtime(true); $this->sorted = false; } public function contains(TimerInterface $timer) { - return isset($this->timers[spl_oject_hash($timer)]); + return isset($this->timers[\spl_object_hash($timer)]); } public function cancel(TimerInterface $timer) { - $id = spl_object_hash($timer); + $id = \spl_object_hash($timer); unset($this->timers[$id], $this->schedule[$id]); } @@ -53,15 +53,15 @@ public function getFirst() // ensure timers are sorted to simply accessing next (first) one if (!$this->sorted) { $this->sorted = true; - asort($this->schedule); + \asort($this->schedule); } - return reset($this->schedule); + return \reset($this->schedule); } public function isEmpty() { - return count($this->timers) === 0; + return \count($this->timers) === 0; } public function tick() @@ -69,7 +69,7 @@ public function tick() // ensure timers are sorted so we can execute in order if (!$this->sorted) { $this->sorted = true; - asort($this->schedule); + \asort($this->schedule); } $time = $this->updateTime(); @@ -86,7 +86,7 @@ public function tick() } $timer = $this->timers[$id]; - call_user_func($timer->getCallback(), $timer); + \call_user_func($timer->getCallback(), $timer); // re-schedule if this is a periodic timer and it has not been cancelled explicitly already if ($timer->isPeriodic() && isset($this->timers[$id])) { From b048bd729a5e462c5352127bd3cd63ed95dfc8ae Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 13 Jun 2018 15:02:17 +0200 Subject: [PATCH 3/4] Using a real `Timer` instance, since pre-historic PHPUnit versions are being used in CI --- tests/Timer/TimersTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/Timer/TimersTest.php b/tests/Timer/TimersTest.php index d4e6987d..e7681c96 100644 --- a/tests/Timer/TimersTest.php +++ b/tests/Timer/TimersTest.php @@ -2,7 +2,6 @@ namespace React\Tests\EventLoop\Timer; -use React\EventLoop\TimerInterface; use React\Tests\EventLoop\TestCase; use React\EventLoop\Timer\Timer; use React\EventLoop\Timer\Timers; @@ -30,10 +29,8 @@ public function testContains() { $timers = new Timers(); - /** @var TimerInterface $timer1 */ - $timer1 = $this->createMock('React\EventLoop\TimerInterface'); - /** @var TimerInterface $timer2 */ - $timer2 = $this->createMock('React\EventLoop\TimerInterface'); + $timer1 = new Timer(0.1, function () {}); + $timer2 = new Timer(0.1, function () {}); $timers->add($timer1); From 88d35a67c1b4cde4cea28643c1f4a6a52697a1c9 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Thu, 14 Jun 2018 03:01:01 +0200 Subject: [PATCH 4/4] Replaced constant references with fully qualified constant references --- src/ExtEventLoop.php | 4 ++-- src/ExtLibeventLoop.php | 14 +++++++------- src/Factory.php | 2 +- src/StreamSelectLoop.php | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ExtEventLoop.php b/src/ExtEventLoop.php index a6153505..fd403d4a 100644 --- a/src/ExtEventLoop.php +++ b/src/ExtEventLoop.php @@ -69,7 +69,7 @@ public function addReadStream($stream, $listener) // ext-event does not increase refcount on stream resources for PHP 7+ // manually keep track of stream resource to prevent premature garbage collection - if (PHP_VERSION_ID >= 70000) { + if (\PHP_VERSION_ID >= 70000) { $this->readRefs[$key] = $stream; } } @@ -88,7 +88,7 @@ public function addWriteStream($stream, $listener) // ext-event does not increase refcount on stream resources for PHP 7+ // manually keep track of stream resource to prevent premature garbage collection - if (PHP_VERSION_ID >= 70000) { + if (\PHP_VERSION_ID >= 70000) { $this->writeRefs[$key] = $stream; } } diff --git a/src/ExtLibeventLoop.php b/src/ExtLibeventLoop.php index ddd66569..55c2fca0 100644 --- a/src/ExtLibeventLoop.php +++ b/src/ExtLibeventLoop.php @@ -74,7 +74,7 @@ public function addReadStream($stream, $listener) } $event = \event_new(); - \event_set($event, $stream, EV_PERSIST | EV_READ, $this->streamCallback); + \event_set($event, $stream, \EV_PERSIST | \EV_READ, $this->streamCallback); \event_base_set($event, $this->eventBase); \event_add($event); @@ -90,7 +90,7 @@ public function addWriteStream($stream, $listener) } $event = \event_new(); - \event_set($event, $stream, EV_PERSIST | EV_WRITE, $this->streamCallback); + \event_set($event, $stream, \EV_PERSIST | \EV_WRITE, $this->streamCallback); \event_base_set($event, $this->eventBase); \event_add($event); @@ -170,7 +170,7 @@ public function addSignal($signal, $listener) if (!isset($this->signalEvents[$signal])) { $this->signalEvents[$signal] = \event_new(); - \event_set($this->signalEvents[$signal], $signal, EV_PERSIST | EV_SIGNAL, array($this->signals, 'call')); + \event_set($this->signalEvents[$signal], $signal, \EV_PERSIST | \EV_SIGNAL, array($this->signals, 'call')); \event_base_set($this->signalEvents[$signal], $this->eventBase); \event_add($this->signalEvents[$signal]); } @@ -194,9 +194,9 @@ public function run() while ($this->running) { $this->futureTickQueue->tick(); - $flags = EVLOOP_ONCE; + $flags = \EVLOOP_ONCE; if (!$this->running || !$this->futureTickQueue->isEmpty()) { - $flags |= EVLOOP_NONBLOCK; + $flags |= \EVLOOP_NONBLOCK; } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) { break; } @@ -271,11 +271,11 @@ private function createStreamCallback() $this->streamCallback = function ($stream, $flags) use (&$read, &$write) { $key = (int) $stream; - if (EV_READ === (EV_READ & $flags) && isset($read[$key])) { + if (\EV_READ === (\EV_READ & $flags) && isset($read[$key])) { \call_user_func($read[$key], $stream); } - if (EV_WRITE === (EV_WRITE & $flags) && isset($write[$key])) { + if (\EV_WRITE === (\EV_WRITE & $flags) && isset($write[$key])) { \call_user_func($write[$key], $stream); } }; diff --git a/src/Factory.php b/src/Factory.php index 48801466..763c077b 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -30,7 +30,7 @@ public static function create() return new ExtEvLoop(); } elseif (\class_exists('EventBase', false)) { return new ExtEventLoop(); - } elseif (\function_exists('event_base_new') && PHP_VERSION_ID < 70000) { + } elseif (\function_exists('event_base_new') && \PHP_VERSION_ID < 70000) { // only use ext-libevent on PHP < 7 for now return new ExtLibeventLoop(); } diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index 7b822e01..625b6fb6 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -163,7 +163,7 @@ public function removeSignal($signal, $listener) $this->signals->remove($signal, $listener); if ($this->signals->count($signal) === 0) { - \pcntl_signal($signal, SIG_DFL); + \pcntl_signal($signal, \SIG_DFL); } } @@ -190,7 +190,7 @@ public function run() // Ensure we do not exceed maximum integer size, which may // cause the loop to tick once every ~35min on 32bit systems. $timeout *= self::MICROSECONDS_PER_SECOND; - $timeout = $timeout > PHP_INT_MAX ? PHP_INT_MAX : (int)$timeout; + $timeout = $timeout > \PHP_INT_MAX ? \PHP_INT_MAX : (int)$timeout; } // The only possible event is stream or signal activity, so wait forever ...