diff --git a/src/StreamSelectLoop.php b/src/StreamSelectLoop.php index 4b1f81c1..9e78dc03 100644 --- a/src/StreamSelectLoop.php +++ b/src/StreamSelectLoop.php @@ -287,8 +287,28 @@ private function streamSelect(array &$read, array &$write, $timeout) } } - // suppress warnings that occur, when stream_select is interrupted by a signal - $ret = @\stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); + /** @var ?callable $previous */ + $previous = \set_error_handler(function ($errno, $errstr) use (&$previous) { + // suppress warnings that occur when `stream_select()` is interrupted by a signal + $eintr = \defined('SOCKET_EINTR') ? \SOCKET_EINTR : 4; + if ($errno === \E_WARNING && \strpos($errstr, '[' . $eintr .']: ') !== false) { + return; + } + + // forward any other error to registered error handler or print warning + return ($previous !== null) ? \call_user_func_array($previous, \func_get_args()) : false; + }); + + try { + $ret = \stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); + \restore_error_handler(); + } catch (\Throwable $e) { // @codeCoverageIgnoreStart + \restore_error_handler(); + throw $e; + } catch (\Exception $e) { + \restore_error_handler(); + throw $e; + } // @codeCoverageIgnoreEnd if ($except) { $write = \array_merge($write, $except); diff --git a/tests/StreamSelectLoopTest.php b/tests/StreamSelectLoopTest.php index d6800c5e..80197468 100644 --- a/tests/StreamSelectLoopTest.php +++ b/tests/StreamSelectLoopTest.php @@ -40,6 +40,85 @@ public function testStreamSelectTimeoutEmulation() $this->assertGreaterThan(0.04, $interval); } + public function testStreamSelectReportsWarningForStreamWithFilter() + { + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('Not supported on legacy HHVM'); + } + + $stream = tmpfile(); + stream_filter_append($stream, 'string.rot13'); + + $this->loop->addReadStream($stream, $this->expectCallableNever()); + + $loop = $this->loop; + $this->loop->futureTick(function () use ($loop, $stream) { + $loop->futureTick(function () use ($loop, $stream) { + $loop->removeReadStream($stream); + }); + }); + + $error = null; + $previous = set_error_handler(function ($_, $errstr) use (&$error) { + $error = $errstr; + }); + + try { + $this->loop->run(); + } catch (\ValueError $e) { + // ignore ValueError for PHP 8+ due to empty stream array + } + + restore_error_handler(); + + $this->assertNotNull($error); + + $now = set_error_handler(function () { }); + restore_error_handler(); + $this->assertEquals($previous, $now); + } + + public function testStreamSelectThrowsWhenCustomErrorHandlerThrowsForStreamWithFilter() + { + if (defined('HHVM_VERSION')) { + $this->markTestSkipped('Not supported on legacy HHVM'); + } + + $stream = tmpfile(); + stream_filter_append($stream, 'string.rot13'); + + $this->loop->addReadStream($stream, $this->expectCallableNever()); + + $loop = $this->loop; + $this->loop->futureTick(function () use ($loop, $stream) { + $loop->futureTick(function () use ($loop, $stream) { + $loop->removeReadStream($stream); + }); + }); + + $previous = set_error_handler(function ($_, $errstr) { + throw new \RuntimeException($errstr); + }); + + $e = null; + try { + $this->loop->run(); + restore_error_handler(); + $this->fail(); + } catch (\RuntimeException $e) { + restore_error_handler(); + } catch (\ValueError $e) { + restore_error_handler(); // PHP 8+ + $e = $e->getPrevious(); + } + + $this->assertInstanceOf('RuntimeException', $e); + + $now = set_error_handler(function () { }); + restore_error_handler(); + $this->assertEquals($previous, $now); + } + public function signalProvider() { return array( pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy