From f058672e6f475471cf7b68dd7d59a852ad1907e0 Mon Sep 17 00:00:00 2001 From: Zach Borboa Date: Sun, 16 Nov 2025 14:58:13 -0500 Subject: [PATCH] Improve MultiCurl::waitUntilRequestQuotaAvailable (#1016) * Include keyword * Use numeric literal separators * Improve waitUntilRequestQuotaAvailable using new TimeUtil --- README.md | 2 +- src/Curl/MultiCurl.php | 37 ++++++++--------- src/Curl/TimeUtil.php | 61 +++++++++++++++++++++++++++++ tests/PHPCurlClass/TimeUtilTest.php | 60 ++++++++++++++++++++++++++++ tests/server.php | 2 +- 5 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 src/Curl/TimeUtil.php create mode 100644 tests/PHPCurlClass/TimeUtilTest.php diff --git a/README.md b/README.md index d78203e..7048713 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Installation instructions to use the `composer` command can be found on https:// ### 📋 Requirements -PHP Curl Class works with PHP 8.4, 8.3, 8.2, 8.1, and 8.0. +PHP Curl Class works with PHP versions 8.4, 8.3, 8.2, 8.1, and 8.0. ### 🚀 Quick Start and Examples diff --git a/src/Curl/MultiCurl.php b/src/Curl/MultiCurl.php index 1e2193f..6595b71 100644 --- a/src/Curl/MultiCurl.php +++ b/src/Curl/MultiCurl.php @@ -687,7 +687,7 @@ class MultiCurl extends BaseCurl // pending requests to have more accurate start times. Without a shorter timeout, it can be nearly a // full second before available request quota is rechecked and pending requests can be initialized. if (curl_multi_select($this->multiCurl, 0.2) === -1) { - usleep(100000); + usleep(100_000); } curl_multi_exec($this->multiCurl, $active); @@ -944,27 +944,28 @@ class MultiCurl extends BaseCurl */ private function waitUntilRequestQuotaAvailable() { - $sleep_until = (float)($this->currentStartTime + $this->intervalSeconds); - $sleep_seconds = $sleep_until - microtime(true); + $sleep_until = TimeUtil::getSleepUntilMicrotime( + $this->currentStartTime, + $this->intervalSeconds, + ); - // Avoid using time_sleep_until() as it appears to be less precise and not sleep long enough. - // Avoid using usleep(): "Values larger than 1000000 (i.e. sleeping for - // more than a second) may not be supported by the operating system. - // Use sleep() instead." - $sleep_seconds_int = (int)$sleep_seconds; - if ($sleep_seconds_int >= 1) { - sleep($sleep_seconds_int); + $current_microtime = microtime(true); + $sleep_seconds = TimeUtil::getSleepSecondsUntilMicrotime( + $sleep_until, + $current_microtime, + ); + + list($whole_seconds, $microseconds_remainder) = TimeUtil::getWholeAndRemainderSeconds($sleep_seconds); + + if ($whole_seconds >= 1) { + sleep($whole_seconds); + } + + if ($microseconds_remainder > 0) { + usleep($microseconds_remainder); } - // Ensure that enough time has passed as usleep() may not have waited long enough. $this->currentStartTime = microtime(true); - if ($this->currentStartTime < $sleep_until) { - do { - usleep(1000000 / 4); - $this->currentStartTime = microtime(true); - } while ($this->currentStartTime < $sleep_until); - } - $this->currentRequestCount = 0; } diff --git a/src/Curl/TimeUtil.php b/src/Curl/TimeUtil.php new file mode 100644 index 0000000..38620d0 --- /dev/null +++ b/src/Curl/TimeUtil.php @@ -0,0 +1,61 @@ +assertEquals( + (float)1_750_000_060.123456, + $sleep_until_microtime, + ); + } + + public function testGetSleepSecondsUntilMicrotime() + { + $sleep_until_microtime = (float)1_750_000_060.123456; + $current_microtime = (float)1_750_000_044.999999; + + $sleep_seconds = TimeUtil::getSleepSecondsUntilMicrotime( + $sleep_until_microtime, + $current_microtime, + ); + + $this->assertEquals( + (float)15.123457, + $sleep_seconds, + ); + } + + public function testGetWholeAndRemainderSeconds() + { + $sleep_seconds = (float)15.123457; + + list($whole_seconds, $microseconds_remainder) = TimeUtil::getWholeAndRemainderSeconds( + $sleep_seconds, + ); + + $this->assertEquals(15, $whole_seconds); + $this->assertEquals(123457, $microseconds_remainder); + } +} diff --git a/tests/server.php b/tests/server.php index c7a701e..ceb7da4 100644 --- a/tests/server.php +++ b/tests/server.php @@ -323,7 +323,7 @@ if ($test === 'http_basic_auth') { $dots_printed = 0; while (true) { - usleep(1000000 / 100); + usleep(1_000_000 / 100); $elapsed = microtime(true) - $start; $dots_to_print = floor($elapsed) - $dots_printed;