From 941af7996d5f96244e7c29c00a8b4a8f2ef08ef5 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 8 Nov 2025 23:03:28 +0100 Subject: [PATCH 1/4] [3.x] Run CI jobs on PHP8.5 --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 871d3f4e..7bde850f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: strategy: matrix: php: + - 8.5 - 8.4 - 8.3 - 8.2 @@ -44,6 +45,8 @@ jobs: strategy: matrix: php: + - 8.5 + - 8.4 - 8.3 - 8.2 - 8.1 @@ -78,6 +81,7 @@ jobs: strategy: matrix: php: + - 8.5 - 8.4 - 8.3 - 8.2 From 5d698a2b5f375896345ab06f4033c512421905c0 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 8 Nov 2025 23:08:13 +0100 Subject: [PATCH 2/4] [3.x] Fix ext-uv int into float overflow logic for PHP8.5 This code introduced in #196 relied on behavior that has been changed in PHP8.5 by: https://wiki.php.net/rfc/warnings-php-8-5#casting_out_of_range_floats_to_int --- src/ExtUvLoop.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ExtUvLoop.php b/src/ExtUvLoop.php index e9e79524..735f697d 100644 --- a/src/ExtUvLoop.php +++ b/src/ExtUvLoop.php @@ -326,9 +326,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." ); From d1a83a2e777c04a8e7357f7c86ab7307cc89d78e Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 8 Nov 2025 23:15:53 +0100 Subject: [PATCH 3/4] [3.x] Fix reflection setAccessible deprecatoin warnings In PHP8.1 ReflectionProperty::setAccessible was made a no-op through https://wiki.php.net/rfc/make-reflection-setaccessible-no-op in PHP8.5 it is now throwing a deprecation warning by: https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_reflectionsetaccessible --- tests/LoopTest.php | 52 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/tests/LoopTest.php b/tests/LoopTest.php index 08e2107e..f5b3cd31 100644 --- a/tests/LoopTest.php +++ b/tests/LoopTest.php @@ -42,7 +42,9 @@ public function testStaticAddReadStreamCallsAddReadStreamOnLoopInstance() public function testStaticAddReadStreamWithNoDefaultLoopCallsAddReadStreamOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, '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'); @@ -68,7 +70,9 @@ public function testStaticAddWriteStreamCallsAddWriteStreamOnLoopInstance() public function testStaticAddWriteStreamWithNoDefaultLoopCallsAddWriteStreamOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, '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'); @@ -93,7 +97,9 @@ public function testStaticRemoveReadStreamCallsRemoveReadStreamOnLoopInstance() public function testStaticRemoveReadStreamWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = tmpfile(); @@ -117,7 +123,9 @@ public function testStaticRemoveWriteStreamCallsRemoveWriteStreamOnLoopInstance( public function testStaticRemoveWriteStreamWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $stream = tmpfile(); @@ -145,7 +153,9 @@ public function testStaticAddTimerCallsAddTimerOnLoopInstanceAndReturnsTimerInst public function testStaticAddTimerWithNoDefaultLoopCallsAddTimerOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $interval = 1.0; @@ -175,7 +185,9 @@ public function testStaticAddPeriodicTimerCallsAddPeriodicTimerOnLoopInstanceAnd public function testStaticAddPeriodicTimerWithNoDefaultLoopCallsAddPeriodicTimerOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $interval = 1.0; @@ -202,7 +214,9 @@ public function testStaticCancelTimerCallsCancelTimerOnLoopInstance() public function testStaticCancelTimerWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $timer = $this->createMock(TimerInterface::class); @@ -226,7 +240,9 @@ public function testStaticFutureTickCallsFutureTickOnLoopInstance() public function testStaticFutureTickWithNoDefaultLoopCallsFutureTickOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $listener = function () { }; @@ -255,7 +271,9 @@ public function testStaticAddSignalWithNoDefaultLoopCallsAddSignalOnNewLoopInsta } $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $signal = 1; @@ -285,7 +303,9 @@ public function testStaticRemoveSignalCallsRemoveSignalOnLoopInstance() public function testStaticRemoveSignalWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); $signal = 1; @@ -308,7 +328,9 @@ public function testStaticRunCallsRunOnLoopInstance() public function testStaticRunWithNoDefaultLoopCallsRunsOnNewLoopInstance() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); Loop::run(); @@ -329,7 +351,9 @@ public function testStaticStopCallsStopOnLoopInstance() public function testStaticStopCallWithNoDefaultLoopIsNoOp() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); Loop::stop(); @@ -344,7 +368,9 @@ public function testStaticStopCallWithNoDefaultLoopIsNoOp() public function unsetLoopFromLoopAccessor() { $ref = new \ReflectionProperty(Loop::class, 'instance'); - $ref->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $ref->setAccessible(true); + } $ref->setValue(null, null); } } From 143445ea16bbaa9a99f851b0cb1defba04078009 Mon Sep 17 00:00:00 2001 From: Cees-Jan Kiewiet Date: Sat, 8 Nov 2025 23:19:19 +0100 Subject: [PATCH 4/4] [3.x] Fix SPL SplObjectStorage deprecations in PHP8.5 the SplObjectStorage::contains, SplObjectStorage::attach, and SplObjectStorage::detach methods have been deprecated through https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_splobjectstoragecontains_splobjectstorageattach_and_splobjectstoragedetach --- src/ExtEvLoop.php | 8 ++++---- src/ExtEventLoop.php | 8 ++++---- src/ExtUvLoop.php | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ExtEvLoop.php b/src/ExtEvLoop.php index 363ad0c4..a069dd18 100644 --- a/src/ExtEvLoop.php +++ b/src/ExtEvLoop.php @@ -141,13 +141,13 @@ public function addTimer($interval, $callback) $callback = function () use ($timer) { \call_user_func($timer->getCallback(), $timer); - if ($this->timers->contains($timer)) { + if ($this->timers->offsetExists($timer)) { $this->cancelTimer($timer); } }; $event = $this->loop->timer($timer->getInterval(), 0.0, $callback); - $this->timers->attach($timer, $event); + $this->timers->offsetSet($timer, $event); return $timer; } @@ -161,7 +161,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; } @@ -174,7 +174,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 d6f24b2a..d18fb16c 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 = []; @@ -153,9 +153,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); } } @@ -238,7 +238,7 @@ private function createTimerCallback() $this->timerCallback = function ($_, $__, $timer) { \call_user_func($timer->getCallback(), $timer); - if (!$timer->isPeriodic() && $this->timerEvents->contains($timer)) { + if (!$timer->isPeriodic() && $this->timerEvents->offsetExists($timer)) { $this->cancelTimer($timer); } }; diff --git a/src/ExtUvLoop.php b/src/ExtUvLoop.php index 735f697d..fd52c354 100644 --- a/src/ExtUvLoop.php +++ b/src/ExtUvLoop.php @@ -117,13 +117,13 @@ public function addTimer($interval, $callback) $callback = function () use ($timer) { \call_user_func($timer->getCallback(), $timer); - if ($this->timers->contains($timer)) { + if ($this->timers->offsetExists($timer)) { $this->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), @@ -147,7 +147,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, @@ -165,7 +165,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); } }