diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0755cde8..fa78b8cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,12 @@ on: jobs: PHPUnit: name: PHPUnit (PHP ${{ matrix.php }}) - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: php: + - 8.5 + - 8.4 - 8.3 - 8.2 - 8.1 @@ -32,7 +34,7 @@ jobs: coverage: xdebug ini-file: development ini-values: disable_functions='' # do not disable PCNTL functions on PHP < 8.1 - extensions: sockets, pcntl ${{ matrix.php >= 5.6 && ', event' || '' }} ${{ matrix.php >= 5.4 && ', ev' || '' }} + extensions: sockets, pcntl ${{ matrix.php >= 5.6 && ', event' || '' }} ${{ matrix.php >= 5.4 && (matrix.php < 8.0 && ', ev-1.1.5' || ', ev') || '' }} env: fail-fast: true # fail step if any extension can not be installed - run: composer install @@ -43,11 +45,13 @@ jobs: PHPUnit-Unstable: name: PHPUnit (Unstable PHP ${{ matrix.php }}) - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 continue-on-error: true strategy: matrix: php: + - 8.5 + - 8.4 - 8.3 - 8.2 - 8.1 @@ -77,8 +81,8 @@ jobs: if: ${{ matrix.php >= 7.0 }} - name: Install legacy ext-libevent on PHP < 7.0 run: | - sudo apt-get update && sudo apt-get install libevent-dev - curl http://pecl.php.net/get/libevent-0.1.0.tgz | tar -xz + sudo apt-get update && sudo apt --fix-broken install && sudo apt-get install libevent-dev + curl https://pecl.php.net/get/libevent-0.1.0.tgz | tar -xz pushd libevent-0.1.0 phpize ./configure @@ -111,6 +115,8 @@ jobs: strategy: matrix: php: + - 8.5 + - 8.4 - 8.3 - 8.2 - 8.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index e634b12e..7d419095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.6.0 (2025-11-17) + +* Feature: Improve PHP 8.5+ support by avoiding deprecated method calls. + (#280 and #282 by @WyriHaximus) + ## 1.5.0 (2023-11-13) * Feature: Improve performance by using `spl_object_id()` on PHP 7.2+. diff --git a/README.md b/README.md index 88a3e18b..bbdf1cff 100644 --- a/README.md +++ b/README.md @@ -889,7 +889,7 @@ This project follows [SemVer](https://semver.org/). This will install the latest supported version: ```bash -composer require react/event-loop:^1.5 +composer require react/event-loop:^1.6 ``` See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. diff --git a/src/ExtEvLoop.php b/src/ExtEvLoop.php index a3fcec68..7689ff57 100644 --- a/src/ExtEvLoop.php +++ b/src/ExtEvLoop.php @@ -143,13 +143,13 @@ public function addTimer($interval, $callback) $callback = function () use ($timer, $timers, $that) { \call_user_func($timer->getCallback(), $timer); - if ($timers->contains($timer)) { + if ($timers->offsetExists($timer)) { $that->cancelTimer($timer); } }; $event = $this->loop->timer($timer->getInterval(), 0.0, $callback); - $this->timers->attach($timer, $event); + $this->timers->offsetSet($timer, $event); return $timer; } @@ -163,7 +163,7 @@ public function addPeriodicTimer($interval, $callback) }; $event = $this->loop->timer($timer->getInterval(), $timer->getInterval(), $callback); - $this->timers->attach($timer, $event); + $this->timers->offsetSet($timer, $event); return $timer; } @@ -176,7 +176,7 @@ public function cancelTimer(TimerInterface $timer) $event = $this->timers[$timer]; $event->stop(); - $this->timers->detach($timer); + $this->timers->offsetUnset($timer); } public function futureTick($listener) diff --git a/src/ExtEventLoop.php b/src/ExtEventLoop.php index b162a402..2f26d746 100644 --- a/src/ExtEventLoop.php +++ b/src/ExtEventLoop.php @@ -64,7 +64,7 @@ public function __destruct() { // explicitly clear all references to Event objects to prevent SEGFAULTs on Windows foreach ($this->timerEvents as $timer) { - $this->timerEvents->detach($timer); + $this->timerEvents->offsetUnset($timer); } $this->readEvents = array(); @@ -157,9 +157,9 @@ public function addPeriodicTimer($interval, $callback) public function cancelTimer(TimerInterface $timer) { - if ($this->timerEvents->contains($timer)) { + if ($this->timerEvents->offsetExists($timer)) { $this->timerEvents[$timer]->free(); - $this->timerEvents->detach($timer); + $this->timerEvents->offsetUnset($timer); } } @@ -243,7 +243,7 @@ private function createTimerCallback() $this->timerCallback = function ($_, $__, $timer) use ($timers) { \call_user_func($timer->getCallback(), $timer); - if (!$timer->isPeriodic() && $timers->contains($timer)) { + if (!$timer->isPeriodic() && $timers->offsetExists($timer)) { $this->cancelTimer($timer); } }; diff --git a/src/ExtUvLoop.php b/src/ExtUvLoop.php index 4434720d..29aa86b4 100644 --- a/src/ExtUvLoop.php +++ b/src/ExtUvLoop.php @@ -119,13 +119,13 @@ public function addTimer($interval, $callback) $callback = function () use ($timer, $timers, $that) { \call_user_func($timer->getCallback(), $timer); - if ($timers->contains($timer)) { + if ($timers->offsetExists($timer)) { $that->cancelTimer($timer); } }; $event = \uv_timer_init($this->uv); - $this->timers->attach($timer, $event); + $this->timers->offsetSet($timer, $event); \uv_timer_start( $event, $this->convertFloatSecondsToMilliseconds($interval), @@ -149,7 +149,7 @@ public function addPeriodicTimer($interval, $callback) $interval = $this->convertFloatSecondsToMilliseconds($interval); $event = \uv_timer_init($this->uv); - $this->timers->attach($timer, $event); + $this->timers->offsetSet($timer, $event); \uv_timer_start( $event, $interval, @@ -167,7 +167,7 @@ public function cancelTimer(TimerInterface $timer) { if (isset($this->timers[$timer])) { @\uv_timer_stop($this->timers[$timer]); - $this->timers->detach($timer); + $this->timers->offsetUnset($timer); } } @@ -329,9 +329,17 @@ private function convertFloatSecondsToMilliseconds($interval) } $maxValue = (int) (\PHP_INT_MAX / 1000); - $intInterval = (int) $interval; + $intervalOverflow = false; + if (PHP_VERSION_ID > 80499 && $interval >= \PHP_INT_MAX + 1) { + $intervalOverflow = true; + } else { + $intInterval = (int) $interval; + if (($intInterval <= 0 && $interval > 1) || $intInterval >= $maxValue) { + $intervalOverflow = true; + } + } - if (($intInterval <= 0 && $interval > 1) || $intInterval >= $maxValue) { + if ($intervalOverflow) { throw new \InvalidArgumentException( "Interval overflow, value must be lower than '{$maxValue}', but '{$interval}' passed." ); diff --git a/tests/LoopTest.php b/tests/LoopTest.php index 42f85244..25b6e855 100644 --- a/tests/LoopTest.php +++ b/tests/LoopTest.php @@ -64,7 +64,9 @@ public function testStaticAddReadStreamCallsAddReadStreamOnLoopInstance() public function testStaticAddReadStreamWithNoDefaultLoopCallsAddReadStreamOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = stream_socket_server('127.0.0.1:0'); @@ -90,7 +92,9 @@ public function testStaticAddWriteStreamCallsAddWriteStreamOnLoopInstance() public function testStaticAddWriteStreamWithNoDefaultLoopCallsAddWriteStreamOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = stream_socket_server('127.0.0.1:0'); @@ -115,7 +119,9 @@ public function testStaticRemoveReadStreamCallsRemoveReadStreamOnLoopInstance() public function testStaticRemoveReadStreamWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = tmpfile(); @@ -139,7 +145,9 @@ public function testStaticRemoveWriteStreamCallsRemoveWriteStreamOnLoopInstance( public function testStaticRemoveWriteStreamWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = tmpfile(); @@ -167,7 +175,9 @@ public function testStaticAddTimerCallsAddTimerOnLoopInstanceAndReturnsTimerInst public function testStaticAddTimerWithNoDefaultLoopCallsAddTimerOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $interval = 1.0; @@ -197,7 +207,9 @@ public function testStaticAddPeriodicTimerCallsAddPeriodicTimerOnLoopInstanceAnd public function testStaticAddPeriodicTimerWithNoDefaultLoopCallsAddPeriodicTimerOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $interval = 1.0; @@ -224,7 +236,9 @@ public function testStaticCancelTimerCallsCancelTimerOnLoopInstance() public function testStaticCancelTimerWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock(); @@ -248,7 +262,9 @@ public function testStaticFutureTickCallsFutureTickOnLoopInstance() public function testStaticFutureTickWithNoDefaultLoopCallsFutureTickOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $listener = function () { }; @@ -277,7 +293,9 @@ public function testStaticAddSignalWithNoDefaultLoopCallsAddSignalOnNewLoopInsta } $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $signal = 1; @@ -307,7 +325,9 @@ public function testStaticRemoveSignalCallsRemoveSignalOnLoopInstance() public function testStaticRemoveSignalWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $signal = 1; @@ -330,7 +350,9 @@ public function testStaticRunCallsRunOnLoopInstance() public function testStaticRunWithNoDefaultLoopCallsRunsOnNewLoopInstance() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); Loop::run(); @@ -351,7 +373,9 @@ public function testStaticStopCallsStopOnLoopInstance() public function testStaticStopCallWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); Loop::stop(); @@ -366,7 +390,9 @@ public function testStaticStopCallWithNoDefaultLoopIsNoOp() public function unsetLoopFromLoopAccessor() { $ref = new \ReflectionProperty('React\EventLoop\Loop', 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); } }