From 10c230387fd1ab2bcf495e6c1f7f40de12e99f33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:45:06 -0500 Subject: [PATCH 01/17] chore(deps-dev): bump slevomat/coding-standard from 8.18.1 to 8.19.1 --- composer.lock | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/composer.lock b/composer.lock index dd5c4a8..c81c000 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "547976e5e347d3df72e50cd356fff616", + "content-hash": "1e4afb20055fa0b7e6ac7218f0242b5f", "packages": [ { "name": "brick/math", @@ -4546,16 +4546,16 @@ }, { "name": "slevomat/coding-standard", - "version": "8.18.1", + "version": "8.19.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "06b18b3f64979ab31d27c37021838439f3ed5919" + "reference": "458d665acd49009efebd7e0cb385d71ae9ac3220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/06b18b3f64979ab31d27c37021838439f3ed5919", - "reference": "06b18b3f64979ab31d27c37021838439f3ed5919", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/458d665acd49009efebd7e0cb385d71ae9ac3220", + "reference": "458d665acd49009efebd7e0cb385d71ae9ac3220", "shasum": "" }, "require": { @@ -4595,7 +4595,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.18.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.19.1" }, "funding": [ { @@ -4607,7 +4607,7 @@ "type": "tidelift" } ], - "time": "2025-05-22T14:32:30+00:00" + "time": "2025-06-09T17:53:57+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -5870,8 +5870,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.0", - "ext-json": "*" + "php": "^8.0" }, "platform-dev": [], "plugin-api-version": "2.3.0" From e512568297573ae083a3d43f65ae093346c296df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 17:06:57 -0500 Subject: [PATCH 02/17] chore(deps-dev): bump justinrainbow/json-schema from 6.4.1 to 6.4.2 --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index c81c000..dfd11a2 100644 --- a/composer.lock +++ b/composer.lock @@ -1330,16 +1330,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.4.1", + "version": "6.4.2", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "35d262c94959571e8736db1e5c9bc36ab94ae900" + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/35d262c94959571e8736db1e5c9bc36ab94ae900", - "reference": "35d262c94959571e8736db1e5c9bc36ab94ae900", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ce1fd2d47799bb60668643bc6220f6278a4c1d02", + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02", "shasum": "" }, "require": { @@ -1399,9 +1399,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.1" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.2" }, - "time": "2025-04-04T13:08:07+00:00" + "time": "2025-06-03T18:27:04+00:00" }, { "name": "localheinz/diff", From 777e7256c20f09a0057dae24456270cc98e3f6a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 18:07:43 -0500 Subject: [PATCH 03/17] chore(deps-dev): bump captainhook/captainhook from 5.25.2 to 5.25.5 --- composer.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index dfd11a2..f5729e3 100644 --- a/composer.lock +++ b/composer.lock @@ -236,16 +236,16 @@ "packages-dev": [ { "name": "captainhook/captainhook", - "version": "5.25.2", + "version": "5.25.5", "source": { "type": "git", "url": "https://github.com/captainhook-git/captainhook.git", - "reference": "e096240c130557be6d2059881341db7ebd84f653" + "reference": "7b0feb07ae328c83c458175fe19e5cb55634b1fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/e096240c130557be6d2059881341db7ebd84f653", - "reference": "e096240c130557be6d2059881341db7ebd84f653", + "url": "https://api.github.com/repos/captainhook-git/captainhook/zipball/7b0feb07ae328c83c458175fe19e5cb55634b1fb", + "reference": "7b0feb07ae328c83c458175fe19e5cb55634b1fb", "shasum": "" }, "require": { @@ -307,8 +307,8 @@ "prepare-commit-msg" ], "support": { - "issues": "https://github.com/captainhookphp/captainhook/issues", - "source": "https://github.com/captainhook-git/captainhook/tree/5.25.2" + "issues": "https://github.com/captainhook-git/captainhook/issues", + "source": "https://github.com/captainhook-git/captainhook/tree/5.25.5" }, "funding": [ { @@ -316,7 +316,7 @@ "type": "github" } ], - "time": "2025-03-30T17:23:19+00:00" + "time": "2025-06-07T07:44:19+00:00" }, { "name": "captainhook/plugin-composer", @@ -4420,16 +4420,16 @@ }, { "name": "sebastianfeldmann/git", - "version": "3.14.2", + "version": "3.14.3", "source": { "type": "git", "url": "https://github.com/sebastianfeldmann/git.git", - "reference": "bc13c3bab8f67dee26352c94e23a4ee775d9d05b" + "reference": "22584df8df01d95b0700000cfd855779fae7d8ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/bc13c3bab8f67dee26352c94e23a4ee775d9d05b", - "reference": "bc13c3bab8f67dee26352c94e23a4ee775d9d05b", + "url": "https://api.github.com/repos/sebastianfeldmann/git/zipball/22584df8df01d95b0700000cfd855779fae7d8ea", + "reference": "22584df8df01d95b0700000cfd855779fae7d8ea", "shasum": "" }, "require": { @@ -4470,7 +4470,7 @@ ], "support": { "issues": "https://github.com/sebastianfeldmann/git/issues", - "source": "https://github.com/sebastianfeldmann/git/tree/3.14.2" + "source": "https://github.com/sebastianfeldmann/git/tree/3.14.3" }, "funding": [ { @@ -4478,7 +4478,7 @@ "type": "github" } ], - "time": "2025-03-28T19:09:31+00:00" + "time": "2025-06-05T16:05:10+00:00" }, { "name": "seld/jsonlint", From 6b9adff8148bdf9603c419fa13be553e8b78fe07 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 18:29:25 -0500 Subject: [PATCH 04/17] chore(deps-dev): bump squizlabs/php_codesniffer from 3.13.0 to 3.13.1 --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index f5729e3..01576ff 100644 --- a/composer.lock +++ b/composer.lock @@ -4611,16 +4611,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.0", + "version": "3.13.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "65ff2489553b83b4597e89c3b8b721487011d186" + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/65ff2489553b83b4597e89c3b8b721487011d186", - "reference": "65ff2489553b83b4597e89c3b8b721487011d186", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", "shasum": "" }, "require": { @@ -4691,7 +4691,7 @@ "type": "thanks_dev" } ], - "time": "2025-05-11T03:36:00+00:00" + "time": "2025-06-12T15:04:34+00:00" }, { "name": "symfony/console", From e957fd25b3f0745ce4036acceb64fa0d3ad2c78a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 21:13:49 -0500 Subject: [PATCH 05/17] chore(deps-dev): bump sebastianfeldmann/git from 3.14.2 to 3.14.3 From 6bbdb8c0e795c82a7c1d587a46d6eb658ade929a Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sun, 22 Jun 2025 16:59:46 -0500 Subject: [PATCH 06/17] Update Composer lock file --- composer.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.lock b/composer.lock index 01576ff..5d554fd 100644 --- a/composer.lock +++ b/composer.lock @@ -5866,12 +5866,12 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.0" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } From 7abc2f20357c29ef3d87141b54225ed237628d74 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sun, 22 Jun 2025 17:00:32 -0500 Subject: [PATCH 07/17] Ensure tests are properly checking against the previous values --- tests/Generator/UnixTimeGeneratorTest.php | 81 +++++++++++++++++------ 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php index 356f99f..d2d8188 100644 --- a/tests/Generator/UnixTimeGeneratorTest.php +++ b/tests/Generator/UnixTimeGeneratorTest.php @@ -14,6 +14,8 @@ use Ramsey\Uuid\Test\TestCase; class UnixTimeGeneratorTest extends TestCase { + private const ITERATIONS = 2000; + /** * @runInSeparateProcess since values are stored statically on the class * @preserveGlobalState disabled @@ -46,9 +48,13 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -63,9 +69,13 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -79,9 +89,13 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -96,9 +110,13 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -113,16 +131,20 @@ class UnixTimeGeneratorTest extends TestCase $randomGenerator->expects()->generate(16)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); - $randomGenerator->expects()->generate(10)->times(24)->andReturns( + $randomGenerator->allows()->generate(10)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); $unixTimeGenerator = new UnixTimeGenerator($randomGenerator); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -132,6 +154,9 @@ class UnixTimeGeneratorTest extends TestCase */ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDate(): void { + $this->markTestSkipped('Bytes generator is failing to properly increment under these conditions'); + + /* @phpstan-ignore-next-line */ $dateTime = new DateTimeImmutable('now'); /** @var RandomGeneratorInterface&MockInterface $randomGenerator */ @@ -139,16 +164,21 @@ class UnixTimeGeneratorTest extends TestCase $randomGenerator->expects()->generate(16)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); - $randomGenerator->expects()->generate(10)->times(24)->andReturns( + $randomGenerator->allows()->generate(10)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); $unixTimeGenerator = new UnixTimeGenerator($randomGenerator); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; + echo "\n"; } } @@ -163,16 +193,20 @@ class UnixTimeGeneratorTest extends TestCase $randomGenerator->expects()->generate(16)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); - $randomGenerator->expects()->generate(10)->times(24)->andReturns( + $randomGenerator->allows()->generate(10)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } @@ -182,6 +216,9 @@ class UnixTimeGeneratorTest extends TestCase */ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDateFor32BitPath(): void { + $this->markTestSkipped('Bytes generator is failing to properly increment under these conditions'); + + /* @phpstan-ignore-next-line */ $dateTime = new DateTimeImmutable('now'); /** @var RandomGeneratorInterface&MockInterface $randomGenerator */ @@ -189,16 +226,20 @@ class UnixTimeGeneratorTest extends TestCase $randomGenerator->expects()->generate(16)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); - $randomGenerator->expects()->generate(10)->times(24)->andReturns( + $randomGenerator->allows()->generate(10)->andReturns( "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", ); $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4); $previous = ''; - for ($i = 0; $i < 25; $i++) { + for ($i = 0; $i < self::ITERATIONS; $i++) { $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue($bytes > $previous); + $this->assertTrue( + $bytes > $previous, + 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), + ); + $previous = $bytes; } } } From b40c06976336f070cf8c0faad2477933bafd2c78 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 23 Jun 2025 15:27:20 -0500 Subject: [PATCH 08/17] Remove errant echo statement from test. [skip ci] --- tests/Generator/UnixTimeGeneratorTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php index d2d8188..96e0c4d 100644 --- a/tests/Generator/UnixTimeGeneratorTest.php +++ b/tests/Generator/UnixTimeGeneratorTest.php @@ -178,7 +178,6 @@ class UnixTimeGeneratorTest extends TestCase 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), ); $previous = $bytes; - echo "\n"; } } From f2956967f21ea0368a42bde22e95f85c3c70a2f1 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 23 Jun 2025 17:32:33 -0500 Subject: [PATCH 09/17] Update tests for testing bytes "rollover" --- tests/Generator/UnixTimeGeneratorTest.php | 42 +++++++++-------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php index 96e0c4d..8fab598 100644 --- a/tests/Generator/UnixTimeGeneratorTest.php +++ b/tests/Generator/UnixTimeGeneratorTest.php @@ -152,11 +152,8 @@ class UnixTimeGeneratorTest extends TestCase * @runInSeparateProcess since values are stored statically on the class * @preserveGlobalState disabled */ - public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDate(): void + public function testGenerateRollsOverWithAllBitsSetWithSameDate(): void { - $this->markTestSkipped('Bytes generator is failing to properly increment under these conditions'); - - /* @phpstan-ignore-next-line */ $dateTime = new DateTimeImmutable('now'); /** @var RandomGeneratorInterface&MockInterface $randomGenerator */ @@ -170,15 +167,13 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator); - $previous = ''; - for ($i = 0; $i < self::ITERATIONS; $i++) { - $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue( - $bytes > $previous, - 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), - ); - $previous = $bytes; - } + // We can only call this twice before the overflow kicks in, "randomizing" all the bits back to 1's, according to + // our mocked random generator. As a result, we can't run this in a loop like with the other monotonicity tests + // in this class; it starts failing at the third loop. This is okay, since our goal is to test the overflow. + $first = $unixTimeGenerator->generate(null, null, $dateTime); + $second = $unixTimeGenerator->generate(null, null, $dateTime); + + $this->assertTrue($second > $first); } /** @@ -213,11 +208,8 @@ class UnixTimeGeneratorTest extends TestCase * @runInSeparateProcess since values are stored statically on the class * @preserveGlobalState disabled */ - public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDateFor32BitPath(): void + public function testGenerateRollsOverWithAllBitsSetWithSameDateFor32BitPath(): void { - $this->markTestSkipped('Bytes generator is failing to properly increment under these conditions'); - - /* @phpstan-ignore-next-line */ $dateTime = new DateTimeImmutable('now'); /** @var RandomGeneratorInterface&MockInterface $randomGenerator */ @@ -231,14 +223,12 @@ class UnixTimeGeneratorTest extends TestCase $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4); - $previous = ''; - for ($i = 0; $i < self::ITERATIONS; $i++) { - $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertTrue( - $bytes > $previous, - 'Failed on iteration ' . $i . ' when evaluating ' . bin2hex($bytes) . ' > ' . bin2hex($previous), - ); - $previous = $bytes; - } + // We can only call this twice before the overflow kicks in, "randomizing" all the bits back to 1's, according to + // our mocked random generator. As a result, we can't run this in a loop like with the other monotonicity tests + // in this class; it starts failing at the third loop. This is okay, since our goal is to test the overflow. + $first = $unixTimeGenerator->generate(null, null, $dateTime); + $second = $unixTimeGenerator->generate(null, null, $dateTime); + + $this->assertTrue($second > $first); } } From eaa5e16923c9fb594efd76031cfc7ab4110807f8 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 23 Jun 2025 18:01:01 -0500 Subject: [PATCH 10/17] Assert the length of time bytes is 6 --- src/Generator/UnixTimeGenerator.php | 4 +++- tests/Generator/UnixTimeGeneratorTest.php | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Generator/UnixTimeGenerator.php b/src/Generator/UnixTimeGenerator.php index 93320cb..024ed51 100644 --- a/src/Generator/UnixTimeGenerator.php +++ b/src/Generator/UnixTimeGenerator.php @@ -19,6 +19,7 @@ use DateTimeImmutable; use DateTimeInterface; use Ramsey\Uuid\Type\Hexadecimal; +use function assert; use function hash; use function pack; use function str_pad; @@ -81,7 +82,8 @@ class UnixTimeGenerator implements TimeGeneratorInterface $time = str_pad(BigInteger::of($time)->toBytes(false), 6, "\x00", STR_PAD_LEFT); } - /** @var non-empty-string */ + assert(strlen($time) === 6); + return $time . pack('n*', self::$rand[1], self::$rand[2], self::$rand[3], self::$rand[4], self::$rand[5]); } diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php index 8fab598..1d28d82 100644 --- a/tests/Generator/UnixTimeGeneratorTest.php +++ b/tests/Generator/UnixTimeGeneratorTest.php @@ -35,7 +35,11 @@ class UnixTimeGeneratorTest extends TestCase $bytes = $unixTimeGenerator->generate(null, null, $dateTime); - $this->assertSame($expectedBytes, $bytes); + $this->assertSame( + $expectedBytes, + $bytes, + 'Failed asserting that "' . bin2hex($bytes) . '" is equal to "' . bin2hex($expectedBytes) . '"', + ); } /** From dbc810466dcbfcb4b21dc7a01ea9595ceb40d400 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:34:18 -0500 Subject: [PATCH 11/17] chore(deps-dev): bump squizlabs/php_codesniffer from 3.13.1 to 3.13.2 --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 5d554fd..f887c53 100644 --- a/composer.lock +++ b/composer.lock @@ -4611,16 +4611,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.1", + "version": "3.13.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd" + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", - "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", "shasum": "" }, "require": { @@ -4691,7 +4691,7 @@ "type": "thanks_dev" } ], - "time": "2025-06-12T15:04:34+00:00" + "time": "2025-06-17T22:17:01+00:00" }, { "name": "symfony/console", @@ -5866,12 +5866,12 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.0" }, - "platform-dev": {}, - "plugin-api-version": "2.6.0" + "platform-dev": [], + "plugin-api-version": "2.3.0" } From df575bdb79660c28f6969053b904ffbece24ac6a Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sun, 22 Jun 2025 17:58:34 -0500 Subject: [PATCH 12/17] Re-add the @pure annotations These were removed in 691c2c816ea574eab667268eca85a1d9046ea599 but should remain in the code base. --- src/BinaryUtils.php | 4 ++++ src/Builder/DegradedUuidBuilder.php | 2 ++ src/Builder/FallbackBuilder.php | 2 ++ src/Builder/UuidBuilderInterface.php | 2 ++ src/Converter/Number/BigNumberConverter.php | 6 ++++++ .../Number/GenericNumberConverter.php | 7 ++++++- src/Converter/NumberConverterInterface.php | 4 ++++ src/Converter/TimeConverterInterface.php | 4 ++++ src/Generator/DefaultNameGenerator.php | 3 +++ src/Generator/NameGeneratorInterface.php | 2 ++ src/Generator/PeclUuidNameGenerator.php | 3 +++ src/Guid/GuidBuilder.php | 2 ++ src/Lazy/LazyUuidFromString.php | 3 +++ src/Nonstandard/UuidBuilder.php | 2 ++ src/Rfc4122/UuidBuilder.php | 2 ++ src/Uuid.php | 16 +++++++++++++++ src/UuidFactory.php | 20 +++++++++++++++++++ src/UuidFactoryInterface.php | 10 ++++++++++ src/functions.php | 6 ++++++ 19 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/BinaryUtils.php b/src/BinaryUtils.php index 1556cfb..d8aac2e 100644 --- a/src/BinaryUtils.php +++ b/src/BinaryUtils.php @@ -27,6 +27,8 @@ class BinaryUtils * @param int $clockSeq The 16-bit clock sequence value before the variant is applied * * @return int The 16-bit clock sequence multiplexed with the UUID variant + * + * @pure */ public static function applyVariant(int $clockSeq): int { @@ -42,6 +44,8 @@ class BinaryUtils * @param int $version The version to apply to the `time_hi` field * * @return int The 16-bit time_hi field of the timestamp multiplexed with the UUID version number + * + * @pure */ public static function applyVersion(int $timeHi, int $version): int { diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php index 126abd5..40f7b8f 100644 --- a/src/Builder/DegradedUuidBuilder.php +++ b/src/Builder/DegradedUuidBuilder.php @@ -50,6 +50,8 @@ class DegradedUuidBuilder implements UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return DegradedUuid The DegradedUuidBuild returns an instance of Ramsey\Uuid\DegradedUuid + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Builder/FallbackBuilder.php b/src/Builder/FallbackBuilder.php index 4b8d797..e40f778 100644 --- a/src/Builder/FallbackBuilder.php +++ b/src/Builder/FallbackBuilder.php @@ -40,6 +40,8 @@ class FallbackBuilder implements UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return UuidInterface an instance of a UUID object + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Builder/UuidBuilderInterface.php b/src/Builder/UuidBuilderInterface.php index 630cd1d..c409878 100644 --- a/src/Builder/UuidBuilderInterface.php +++ b/src/Builder/UuidBuilderInterface.php @@ -31,6 +31,8 @@ interface UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return UuidInterface Implementations may choose to return more specific instances of UUIDs that implement UuidInterface + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface; } diff --git a/src/Converter/Number/BigNumberConverter.php b/src/Converter/Number/BigNumberConverter.php index 9c51aab..ff4e1cc 100644 --- a/src/Converter/Number/BigNumberConverter.php +++ b/src/Converter/Number/BigNumberConverter.php @@ -34,11 +34,17 @@ class BigNumberConverter implements NumberConverterInterface $this->converter = new GenericNumberConverter(new BrickMathCalculator()); } + /** + * @pure + */ public function fromHex(string $hex): string { return $this->converter->fromHex($hex); } + /** + * @pure + */ public function toHex(string $number): string { return $this->converter->toHex($number); diff --git a/src/Converter/Number/GenericNumberConverter.php b/src/Converter/Number/GenericNumberConverter.php index cb8b331..034dc43 100644 --- a/src/Converter/Number/GenericNumberConverter.php +++ b/src/Converter/Number/GenericNumberConverter.php @@ -29,14 +29,19 @@ class GenericNumberConverter implements NumberConverterInterface { } + /** + * @pure + */ public function fromHex(string $hex): string { return $this->calculator->fromBase($hex, 16)->toString(); } + /** + * @pure + */ public function toHex(string $number): string { - /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ return $this->calculator->toBase(new IntegerObject($number), 16); } } diff --git a/src/Converter/NumberConverterInterface.php b/src/Converter/NumberConverterInterface.php index 98b9baf..63eca6c 100644 --- a/src/Converter/NumberConverterInterface.php +++ b/src/Converter/NumberConverterInterface.php @@ -30,6 +30,8 @@ interface NumberConverterInterface * @param string $hex The hexadecimal string representation to convert * * @return numeric-string String representation of an integer + * + * @pure */ public function fromHex(string $hex): string; @@ -40,6 +42,8 @@ interface NumberConverterInterface * unsigned integers that are greater than `PHP_INT_MAX`. * * @return non-empty-string Hexadecimal string + * + * @pure */ public function toHex(string $number): string; } diff --git a/src/Converter/TimeConverterInterface.php b/src/Converter/TimeConverterInterface.php index 6402407..065e3b7 100644 --- a/src/Converter/TimeConverterInterface.php +++ b/src/Converter/TimeConverterInterface.php @@ -34,6 +34,8 @@ interface TimeConverterInterface * @param string $microseconds A string representation of the micro-seconds associated with the time to calculate * * @return Hexadecimal The full UUID timestamp as a Hexadecimal value + * + * @pure */ public function calculateTime(string $seconds, string $microseconds): Hexadecimal; @@ -44,6 +46,8 @@ interface TimeConverterInterface * of 100-nanosecond intervals since UTC 00:00:00.00, 15 October 1582. * * @return Time An instance of {@see Time} + * + * @pure */ public function convertTime(Hexadecimal $uuidTimestamp): Time; } diff --git a/src/Generator/DefaultNameGenerator.php b/src/Generator/DefaultNameGenerator.php index a73b630..cf37b45 100644 --- a/src/Generator/DefaultNameGenerator.php +++ b/src/Generator/DefaultNameGenerator.php @@ -25,6 +25,9 @@ use function hash; */ class DefaultNameGenerator implements NameGeneratorInterface { + /** + * @pure + */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string { try { diff --git a/src/Generator/NameGeneratorInterface.php b/src/Generator/NameGeneratorInterface.php index d2b20eb..f0fb8da 100644 --- a/src/Generator/NameGeneratorInterface.php +++ b/src/Generator/NameGeneratorInterface.php @@ -30,6 +30,8 @@ interface NameGeneratorInterface * @param string $hashAlgorithm The hashing algorithm to use * * @return string A binary string + * + * @pure */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string; } diff --git a/src/Generator/PeclUuidNameGenerator.php b/src/Generator/PeclUuidNameGenerator.php index 2f6d948..ee77a78 100644 --- a/src/Generator/PeclUuidNameGenerator.php +++ b/src/Generator/PeclUuidNameGenerator.php @@ -29,6 +29,9 @@ use function uuid_parse; */ class PeclUuidNameGenerator implements NameGeneratorInterface { + /** + * @pure + */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string { $uuid = match ($hashAlgorithm) { diff --git a/src/Guid/GuidBuilder.php b/src/Guid/GuidBuilder.php index 836e51a..d5ea663 100644 --- a/src/Guid/GuidBuilder.php +++ b/src/Guid/GuidBuilder.php @@ -49,6 +49,8 @@ class GuidBuilder implements UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return Guid The GuidBuilder returns an instance of Ramsey\Uuid\Guid\Guid + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Lazy/LazyUuidFromString.php b/src/Lazy/LazyUuidFromString.php index e3d4b9c..7ec71c2 100644 --- a/src/Lazy/LazyUuidFromString.php +++ b/src/Lazy/LazyUuidFromString.php @@ -61,6 +61,9 @@ final class LazyUuidFromString implements UuidInterface { } + /** + * @pure + */ public static function fromBytes(string $bytes): self { $base16Uuid = bin2hex($bytes); diff --git a/src/Nonstandard/UuidBuilder.php b/src/Nonstandard/UuidBuilder.php index ded4709..a9885cb 100644 --- a/src/Nonstandard/UuidBuilder.php +++ b/src/Nonstandard/UuidBuilder.php @@ -47,6 +47,8 @@ class UuidBuilder implements UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return Uuid The Nonstandard\UuidBuilder returns an instance of Nonstandard\Uuid + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php index e477528..5c239c2 100644 --- a/src/Rfc4122/UuidBuilder.php +++ b/src/Rfc4122/UuidBuilder.php @@ -60,6 +60,8 @@ class UuidBuilder implements UuidBuilderInterface * @param string $bytes The byte string from which to construct a UUID * * @return Rfc4122UuidInterface UuidBuilder returns instances of Rfc4122UuidInterface + * + * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Uuid.php b/src/Uuid.php index 40ada66..449a789 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -448,6 +448,8 @@ class Uuid implements UuidInterface * @return UuidInterface A UuidInterface instance created from a binary string representation * * @throws InvalidArgumentException + * + * @pure */ public static function fromBytes(string $bytes): UuidInterface { @@ -479,6 +481,8 @@ class Uuid implements UuidInterface * @return UuidInterface A UuidInterface instance created from a hexadecimal string representation * * @throws InvalidArgumentException + * + * @pure */ public static function fromString(string $uuid): UuidInterface { @@ -518,6 +522,8 @@ class Uuid implements UuidInterface * @return UuidInterface A UuidInterface instance created from the Hexadecimal object representing a hexadecimal number * * @throws InvalidArgumentException + * + * @pure */ public static function fromHexadecimal(Hexadecimal $hex): UuidInterface { @@ -541,6 +547,8 @@ class Uuid implements UuidInterface * @return UuidInterface A UuidInterface instance created from the string representation of a 128-bit integer * * @throws InvalidArgumentException + * + * @pure */ public static function fromInteger(string $integer): UuidInterface { @@ -555,6 +563,8 @@ class Uuid implements UuidInterface * @return bool True if the string is a valid UUID, false otherwise * * @phpstan-assert-if-true =non-empty-string $uuid + * + * @pure */ public static function isValid(string $uuid): bool { @@ -606,6 +616,8 @@ class Uuid implements UuidInterface * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 3 UUID + * + * @pure */ public static function uuid3($ns, string $name): UuidInterface { @@ -629,6 +641,8 @@ class Uuid implements UuidInterface * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 5 UUID + * + * @pure */ public static function uuid5($ns, string $name): UuidInterface { @@ -682,6 +696,8 @@ class Uuid implements UuidInterface * and 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return UuidInterface A UuidInterface instance that represents a version 8 UUID + * + * @pure */ public static function uuid8(string $bytes): UuidInterface { diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 1c78a21..19be738 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -252,11 +252,17 @@ class UuidFactory implements UuidFactoryInterface $this->validator = $validator; } + /** + * @pure + */ public function fromBytes(string $bytes): UuidInterface { return $this->codec->decodeBytes($bytes); } + /** + * @pure + */ public function fromString(string $uuid): UuidInterface { $uuid = strtolower($uuid); @@ -264,6 +270,9 @@ class UuidFactory implements UuidFactoryInterface return $this->codec->decode($uuid); } + /** + * @pure + */ public function fromInteger(string $integer): UuidInterface { $hex = $this->numberConverter->toHex($integer); @@ -284,6 +293,9 @@ class UuidFactory implements UuidFactoryInterface return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); } + /** + * @pure + */ public function fromHexadecimal(Hexadecimal $hex): UuidInterface { return $this->codec->decode($hex->__toString()); @@ -312,6 +324,7 @@ class UuidFactory implements UuidFactoryInterface /** * @inheritDoc + * @pure */ public function uuid3($ns, string $name): UuidInterface { @@ -327,6 +340,7 @@ class UuidFactory implements UuidFactoryInterface /** * @inheritDoc + * @pure */ public function uuid5($ns, string $name): UuidInterface { @@ -377,6 +391,8 @@ class UuidFactory implements UuidFactoryInterface * and 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return UuidInterface A UuidInterface instance that represents a version 8 UUID + * + * @pure */ public function uuid8(string $bytes): UuidInterface { @@ -391,6 +407,8 @@ class UuidFactory implements UuidFactoryInterface * @param string $bytes The byte string from which to construct a UUID * * @return UuidInterface An instance of UuidInterface, created from the provided bytes + * + * @pure */ public function uuid(string $bytes): UuidInterface { @@ -406,6 +424,8 @@ class UuidFactory implements UuidFactoryInterface * @param string $hashAlgorithm The hashing algorithm to use when hashing together the namespace and name * * @return UuidInterface An instance of UuidInterface, created by hashing together the provided namespace and name + * + * @pure */ private function uuidFromNsAndName( UuidInterface | string $ns, diff --git a/src/UuidFactoryInterface.php b/src/UuidFactoryInterface.php index 2b77526..5a83a79 100644 --- a/src/UuidFactoryInterface.php +++ b/src/UuidFactoryInterface.php @@ -30,6 +30,8 @@ interface UuidFactoryInterface * @param string $bytes A binary string * * @return UuidInterface A UuidInterface instance created from a binary string representation + * + * @pure */ public function fromBytes(string $bytes): UuidInterface; @@ -55,6 +57,8 @@ interface UuidFactoryInterface * @param string $integer String representation of 128-bit integer * * @return UuidInterface A UuidInterface instance created from the string representation of a 128-bit integer + * + * @pure */ public function fromInteger(string $integer): UuidInterface; @@ -64,6 +68,8 @@ interface UuidFactoryInterface * @param string $uuid A hexadecimal string * * @return UuidInterface A UuidInterface instance created from a hexadecimal string representation + * + * @pure */ public function fromString(string $uuid): UuidInterface; @@ -112,6 +118,8 @@ interface UuidFactoryInterface * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 3 UUID + * + * @pure */ public function uuid3($ns, string $name): UuidInterface; @@ -129,6 +137,8 @@ interface UuidFactoryInterface * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 5 UUID + * + * @pure */ public function uuid5($ns, string $name): UuidInterface; diff --git a/src/functions.php b/src/functions.php index 946cfbc..854c5c5 100644 --- a/src/functions.php +++ b/src/functions.php @@ -62,6 +62,8 @@ function v2( * @param UuidInterface | string $ns The namespace (must be a valid UUID) * * @return non-empty-string Version 3 UUID as a string + * + * @pure */ function v3($ns, string $name): string { @@ -84,6 +86,8 @@ function v4(): string * @param UuidInterface | string $ns The namespace (must be a valid UUID) * * @return non-empty-string Version 5 UUID as a string + * + * @pure */ function v5($ns, string $name): string { @@ -128,6 +132,8 @@ function v7(?DateTimeInterface $dateTime = null): string * 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return non-empty-string Version 8 UUID as a string + * + * @pure */ function v8(string $bytes): string { From aa18ce15d5c59afe01744d2fcfa6ab46a2cf5f3e Mon Sep 17 00:00:00 2001 From: Brandon Morrison Date: Tue, 24 Jun 2025 20:28:52 -0500 Subject: [PATCH 13/17] Fix pure annotations (#605) Coming from https://github.com/ramsey/uuid/pull/603, this is an attempt to fix the errors raised by the current phpstan settings. I went through each of the errors raised by phpstan with the following approach. - If a method is part of an `@immutable` class, we can consider it pure, assuming it only affects internal variables. - If a potentially pure method is calling a class's method that is only swapped during testing (and not during normal usage), then we can consider the calling method pure. - If a class is marked deprecated, don't bother with attempting to mark it pure or immutable. --- src/Builder/DegradedUuidBuilder.php | 2 +- src/Codec/CodecInterface.php | 8 +++++++ src/Codec/GuidStringCodec.php | 3 +++ src/Codec/OrderedTimeCodec.php | 5 +++++ src/Codec/StringCodec.php | 2 ++ src/Codec/TimestampFirstCombCodec.php | 6 ++++++ .../Number/GenericNumberConverter.php | 1 + src/Converter/Time/GenericTimeConverter.php | 12 +++++++---- src/Converter/Time/PhpTimeConverter.php | 12 ++++++++--- src/Converter/Time/UnixTimeConverter.php | 21 +++++++++++++++---- src/Fields/FieldsInterface.php | 2 ++ src/Generator/PeclUuidNameGenerator.php | 5 +++-- src/Guid/GuidBuilder.php | 5 +++++ src/Lazy/LazyUuidFromString.php | 6 ++---- src/Math/BrickMathCalculator.php | 15 +++++++++++-- src/Math/CalculatorInterface.php | 16 ++++++++++++++ src/Nonstandard/Uuid.php | 1 + src/Nonstandard/UuidBuilder.php | 5 +++++ src/Rfc4122/Fields.php | 3 +++ src/Rfc4122/FieldsInterface.php | 4 ++++ src/Rfc4122/MaxTrait.php | 4 ++++ src/Rfc4122/NilTrait.php | 2 ++ src/Rfc4122/UuidBuilder.php | 14 +++++++++++++ src/Rfc4122/Validator.php | 2 ++ src/Rfc4122/VersionTrait.php | 2 ++ src/Type/Hexadecimal.php | 2 ++ src/Type/Integer.php | 2 ++ src/Type/Time.php | 6 ++++++ src/Type/TypeInterface.php | 6 ++++++ src/Uuid.php | 17 ++++++++++++++- src/UuidFactory.php | 2 ++ src/UuidInterface.php | 6 ++++++ src/Validator/GenericValidator.php | 2 ++ src/Validator/ValidatorInterface.php | 2 ++ tests/Builder/FallbackBuilderTest.php | 1 + tests/Codec/GuidStringCodecTest.php | 1 + tests/Codec/OrderedTimeCodecTest.php | 3 +++ tests/Codec/StringCodecTest.php | 2 ++ .../Number/BigNumberConverterTest.php | 2 ++ .../Time/BigNumberTimeConverterTest.php | 2 ++ tests/Converter/Time/PhpTimeConverterTest.php | 2 ++ tests/Encoder/TimestampFirstCombCodecTest.php | 1 + tests/Encoder/TimestampLastCombCodecTest.php | 1 + tests/Generator/DefaultNameGeneratorTest.php | 1 + tests/Generator/PeclUuidNameGeneratorTest.php | 1 + tests/Guid/GuidBuilderTest.php | 1 + tests/Math/BrickMathCalculatorTest.php | 1 + tests/Nonstandard/UuidBuilderTest.php | 1 + tests/Rfc4122/UuidBuilderTest.php | 2 ++ tests/UuidTest.php | 3 +++ tests/benchmark/GuidConversionBench.php | 1 + .../benchmark/NonLazyUuidConversionBench.php | 1 + tests/benchmark/UuidGenerationBench.php | 2 ++ tests/benchmark/UuidStringConversionBench.php | 6 ++++++ 54 files changed, 217 insertions(+), 21 deletions(-) diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php index 40f7b8f..1554a97 100644 --- a/src/Builder/DegradedUuidBuilder.php +++ b/src/Builder/DegradedUuidBuilder.php @@ -51,7 +51,7 @@ class DegradedUuidBuilder implements UuidBuilderInterface * * @return DegradedUuid The DegradedUuidBuild returns an instance of Ramsey\Uuid\DegradedUuid * - * @pure + * @phpstan-impure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { diff --git a/src/Codec/CodecInterface.php b/src/Codec/CodecInterface.php index b3c2436..b1e554e 100644 --- a/src/Codec/CodecInterface.php +++ b/src/Codec/CodecInterface.php @@ -29,6 +29,8 @@ interface CodecInterface * @param UuidInterface $uuid The UUID for which to create a hexadecimal string representation * * @return non-empty-string Hexadecimal string representation of a UUID + * + * @pure */ public function encode(UuidInterface $uuid): string; @@ -38,6 +40,8 @@ interface CodecInterface * @param UuidInterface $uuid The UUID for which to create a binary string representation * * @return non-empty-string Binary string representation of a UUID + * + * @pure */ public function encodeBinary(UuidInterface $uuid): string; @@ -47,6 +51,8 @@ interface CodecInterface * @param string $encodedUuid The hexadecimal string representation to convert into a UuidInterface instance * * @return UuidInterface An instance of a UUID decoded from a hexadecimal string representation + * + * @pure */ public function decode(string $encodedUuid): UuidInterface; @@ -56,6 +62,8 @@ interface CodecInterface * @param string $bytes The binary string representation to convert into a UuidInterface instance * * @return UuidInterface An instance of a UUID decoded from a binary string representation + * + * @pure */ public function decodeBytes(string $bytes): UuidInterface; } diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index 4cab27c..a1bd58a 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -32,6 +32,7 @@ class GuidStringCodec extends StringCodec { public function encode(UuidInterface $uuid): string { + /** @phpstan-ignore possiblyImpure.methodCall */ $hex = bin2hex($uuid->getFields()->getBytes()); /** @var non-empty-string */ @@ -52,8 +53,10 @@ class GuidStringCodec extends StringCodec public function decode(string $encodedUuid): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->getBytes($encodedUuid); + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } diff --git a/src/Codec/OrderedTimeCodec.php b/src/Codec/OrderedTimeCodec.php index c200eb1..f24f71b 100644 --- a/src/Codec/OrderedTimeCodec.php +++ b/src/Codec/OrderedTimeCodec.php @@ -51,12 +51,15 @@ class OrderedTimeCodec extends StringCodec public function encodeBinary(UuidInterface $uuid): string { if ( + /** @phpstan-ignore possiblyImpure.methodCall */ !($uuid->getFields() instanceof Rfc4122FieldsInterface) + /** @phpstan-ignore possiblyImpure.methodCall */ || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME ) { throw new InvalidArgumentException('Expected version 1 (time-based) UUID'); } + /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $uuid->getFields()->getBytes(); return $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5] @@ -85,7 +88,9 @@ class OrderedTimeCodec extends StringCodec $uuid = parent::decodeBytes($rearrangedBytes); if ( + /** @phpstan-ignore possiblyImpure.methodCall */ !($uuid->getFields() instanceof Rfc4122FieldsInterface) + /** @phpstan-ignore possiblyImpure.methodCall */ || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME ) { throw new UnsupportedOperationException( diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index 756d74c..55f4f8b 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -46,6 +46,7 @@ class StringCodec implements CodecInterface public function encode(UuidInterface $uuid): string { + /** @phpstan-ignore possiblyImpure.methodCall */ $hex = bin2hex($uuid->getFields()->getBytes()); /** @var non-empty-string */ @@ -75,6 +76,7 @@ class StringCodec implements CodecInterface */ public function decode(string $encodedUuid): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return $this->builder->build($this, $this->getBytes($encodedUuid)); } diff --git a/src/Codec/TimestampFirstCombCodec.php b/src/Codec/TimestampFirstCombCodec.php index 2835698..e7c8efd 100644 --- a/src/Codec/TimestampFirstCombCodec.php +++ b/src/Codec/TimestampFirstCombCodec.php @@ -55,6 +55,7 @@ class TimestampFirstCombCodec extends StringCodec */ public function encode(UuidInterface $uuid): string { + /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->swapBytes($uuid->getFields()->getBytes()); return sprintf( @@ -83,18 +84,23 @@ class TimestampFirstCombCodec extends StringCodec */ public function decode(string $encodedUuid): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->getBytes($encodedUuid); + /** @phpstan-ignore possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } public function decodeBytes(string $bytes): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } /** * Swaps bytes according to the timestamp-first COMB rules + * + * @pure */ private function swapBytes(string $bytes): string { diff --git a/src/Converter/Number/GenericNumberConverter.php b/src/Converter/Number/GenericNumberConverter.php index 034dc43..dcbc132 100644 --- a/src/Converter/Number/GenericNumberConverter.php +++ b/src/Converter/Number/GenericNumberConverter.php @@ -42,6 +42,7 @@ class GenericNumberConverter implements NumberConverterInterface */ public function toHex(string $number): string { + /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ return $this->calculator->toBase(new IntegerObject($number), 16); } } diff --git a/src/Converter/Time/GenericTimeConverter.php b/src/Converter/Time/GenericTimeConverter.php index f9b176c..d0dd06c 100644 --- a/src/Converter/Time/GenericTimeConverter.php +++ b/src/Converter/Time/GenericTimeConverter.php @@ -54,26 +54,29 @@ class GenericTimeConverter implements TimeConverterInterface public function calculateTime(string $seconds, string $microseconds): Hexadecimal { + /** @phpstan-ignore possiblyImpure.new */ $timestamp = new Time($seconds, $microseconds); // Convert the seconds into a count of 100-nanosecond intervals. $sec = $this->calculator->multiply( $timestamp->getSeconds(), - new IntegerObject(self::SECOND_INTERVALS), + new IntegerObject(self::SECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); // Convert the microseconds into a count of 100-nanosecond intervals. $usec = $this->calculator->multiply( $timestamp->getMicroseconds(), - new IntegerObject(self::MICROSECOND_INTERVALS), + new IntegerObject(self::MICROSECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); // Combine the intervals of seconds and microseconds and add the count of 100-nanosecond intervals from the // Gregorian calendar epoch to the Unix epoch. This gives us the correct count of 100-nanosecond intervals since // the Gregorian calendar epoch for the given seconds and microseconds. /** @var IntegerObject $uuidTime */ + /** @phpstan-ignore possiblyImpure.new */ $uuidTime = $this->calculator->add($sec, $usec, new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)); + /** @phpstan-ignore-next-line phpstan considers CalculatorInterface::toHexidecimal, Hexadecimal:toString impure */ return new Hexadecimal(str_pad($this->calculator->toHexadecimal($uuidTime)->toString(), 16, '0', STR_PAD_LEFT)); } @@ -83,7 +86,7 @@ class GenericTimeConverter implements TimeConverterInterface // epoch. This gives us the number of 100-nanosecond intervals from the Unix epoch, which also includes the microtime. $epochNanoseconds = $this->calculator->subtract( $this->calculator->toInteger($uuidTimestamp), - new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS), + new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); // Convert the 100-nanosecond intervals into seconds and microseconds. @@ -91,11 +94,12 @@ class GenericTimeConverter implements TimeConverterInterface RoundingMode::HALF_UP, 6, $epochNanoseconds, - new IntegerObject(self::SECOND_INTERVALS), + new IntegerObject(self::SECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); $split = explode('.', (string) $unixTimestamp, 2); + /** @phpstan-ignore possiblyImpure.new */ return new Time($split[0], $split[1] ?? 0); } } diff --git a/src/Converter/Time/PhpTimeConverter.php b/src/Converter/Time/PhpTimeConverter.php index a4d6a8c..67dbf88 100644 --- a/src/Converter/Time/PhpTimeConverter.php +++ b/src/Converter/Time/PhpTimeConverter.php @@ -79,8 +79,8 @@ class PhpTimeConverter implements TimeConverterInterface public function calculateTime(string $seconds, string $microseconds): Hexadecimal { - $seconds = new IntegerObject($seconds); - $microseconds = new IntegerObject($microseconds); + $seconds = new IntegerObject($seconds); /** @phpstan-ignore possiblyImpure.new */ + $microseconds = new IntegerObject($microseconds); /** @phpstan-ignore possiblyImpure.new */ // Calculate the count of 100-nanosecond intervals since the Gregorian calendar epoch // for the given seconds and microseconds. @@ -98,7 +98,10 @@ class PhpTimeConverter implements TimeConverterInterface ); } - return new Hexadecimal(str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT)); + /** @phpstan-ignore possiblyImpure.new */ + return new Hexadecimal( + str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT) + ); } public function convertTime(Hexadecimal $uuidTimestamp): Time @@ -114,6 +117,7 @@ class PhpTimeConverter implements TimeConverterInterface return $this->fallbackConverter->convertTime($uuidTimestamp); } + /** @phpstan-ignore possiblyImpure.new */ return new Time($splitTime['sec'], $splitTime['usec']); } @@ -121,6 +125,8 @@ class PhpTimeConverter implements TimeConverterInterface * @param float | int $time The time to split into seconds and microseconds * * @return string[] + * + * @pure */ private function splitTime(float | int $time): array { diff --git a/src/Converter/Time/UnixTimeConverter.php b/src/Converter/Time/UnixTimeConverter.php index 954959d..843efb7 100644 --- a/src/Converter/Time/UnixTimeConverter.php +++ b/src/Converter/Time/UnixTimeConverter.php @@ -42,23 +42,35 @@ class UnixTimeConverter implements TimeConverterInterface public function calculateTime(string $seconds, string $microseconds): Hexadecimal { + /** @phpstan-ignore possiblyImpure.new */ $timestamp = new Time($seconds, $microseconds); // Convert the seconds into milliseconds. - $sec = $this->calculator->multiply($timestamp->getSeconds(), new IntegerObject(self::MILLISECONDS)); + $sec = $this->calculator->multiply( + $timestamp->getSeconds(), + new IntegerObject(self::MILLISECONDS) /** @phpstan-ignore possiblyImpure.new */ + ); // Convert the microseconds into milliseconds; the scale is zero because we need to discard the fractional part. $usec = $this->calculator->divide( RoundingMode::DOWN, // Always round down to stay in the previous millisecond. 0, $timestamp->getMicroseconds(), - new IntegerObject(self::MILLISECONDS), + new IntegerObject(self::MILLISECONDS), /** @phpstan-ignore possiblyImpure.new */ ); /** @var IntegerObject $unixTime */ $unixTime = $this->calculator->add($sec, $usec); - return new Hexadecimal(str_pad($this->calculator->toHexadecimal($unixTime)->toString(), 12, '0', STR_PAD_LEFT)); + /** @phpstan-ignore possiblyImpure.new */ + return new Hexadecimal( + str_pad( + $this->calculator->toHexadecimal($unixTime)->toString(), + 12, + '0', + STR_PAD_LEFT + ) + ); } public function convertTime(Hexadecimal $uuidTimestamp): Time @@ -69,11 +81,12 @@ class UnixTimeConverter implements TimeConverterInterface RoundingMode::HALF_UP, 6, $milliseconds, - new IntegerObject(self::MILLISECONDS), + new IntegerObject(self::MILLISECONDS), /** @phpstan-ignore possiblyImpure.new */ ); $split = explode('.', (string) $unixTimestamp, 2); + /** @phpstan-ignore possiblyImpure.new */ return new Time($split[0], $split[1] ?? '0'); } } diff --git a/src/Fields/FieldsInterface.php b/src/Fields/FieldsInterface.php index f194533..f17ea88 100644 --- a/src/Fields/FieldsInterface.php +++ b/src/Fields/FieldsInterface.php @@ -26,6 +26,8 @@ interface FieldsInterface extends Serializable { /** * Returns the bytes that comprise the fields + * + * @pure */ public function getBytes(): string; } diff --git a/src/Generator/PeclUuidNameGenerator.php b/src/Generator/PeclUuidNameGenerator.php index ee77a78..d13bafc 100644 --- a/src/Generator/PeclUuidNameGenerator.php +++ b/src/Generator/PeclUuidNameGenerator.php @@ -35,13 +35,14 @@ class PeclUuidNameGenerator implements NameGeneratorInterface public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string { $uuid = match ($hashAlgorithm) { - 'md5' => uuid_generate_md5($ns->toString(), $name), - 'sha1' => uuid_generate_sha1($ns->toString(), $name), + 'md5' => uuid_generate_md5($ns->toString(), $name), /** @phpstan-ignore possiblyImpure.functionCall */ + 'sha1' => uuid_generate_sha1($ns->toString(), $name), /** @phpstan-ignore possiblyImpure.functionCall */ default => throw new NameException( sprintf('Unable to hash namespace and name with algorithm \'%s\'', $hashAlgorithm), ), }; + /** @phpstan-ignore possiblyImpure.functionCall */ return (string) uuid_parse($uuid); } } diff --git a/src/Guid/GuidBuilder.php b/src/Guid/GuidBuilder.php index d5ea663..db743d9 100644 --- a/src/Guid/GuidBuilder.php +++ b/src/Guid/GuidBuilder.php @@ -55,17 +55,22 @@ class GuidBuilder implements UuidBuilderInterface public function build(CodecInterface $codec, string $bytes): UuidInterface { try { + /** @phpstan-ignore possiblyImpure.new */ return new Guid($this->buildFields($bytes), $this->numberConverter, $codec, $this->timeConverter); } catch (Throwable $e) { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing + * + * @pure */ protected function buildFields(string $bytes): Fields { + /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } diff --git a/src/Lazy/LazyUuidFromString.php b/src/Lazy/LazyUuidFromString.php index 7ec71c2..372762a 100644 --- a/src/Lazy/LazyUuidFromString.php +++ b/src/Lazy/LazyUuidFromString.php @@ -61,9 +61,6 @@ final class LazyUuidFromString implements UuidInterface { } - /** - * @pure - */ public static function fromBytes(string $bytes): self { $base16Uuid = bin2hex($bytes); @@ -217,7 +214,8 @@ final class LazyUuidFromString implements UuidInterface public function getBytes(): string { - /** @var non-empty-string */ + /** @var non-empty-string + * @phpstan-ignore-next-line Avoiding pure function complaints */ return (string) hex2bin(str_replace('-', '', $this->uuid)); } diff --git a/src/Math/BrickMathCalculator.php b/src/Math/BrickMathCalculator.php index f784c73..869835e 100644 --- a/src/Math/BrickMathCalculator.php +++ b/src/Math/BrickMathCalculator.php @@ -49,9 +49,10 @@ final class BrickMathCalculator implements CalculatorInterface $sum = BigInteger::of($augend->toString()); foreach ($addends as $addend) { - $sum = $sum->plus($addend->toString()); + $sum = $sum->plus($addend->toString()); /** @phpstan-ignore possiblyImpure.methodCall */ } + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.new */ return new IntegerObject((string) $sum); } @@ -60,9 +61,10 @@ final class BrickMathCalculator implements CalculatorInterface $difference = BigInteger::of($minuend->toString()); foreach ($subtrahends as $subtrahend) { - $difference = $difference->minus($subtrahend->toString()); + $difference = $difference->minus($subtrahend->toString()); /** @phpstan-ignore possiblyImpure.methodCall */ } + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.new */ return new IntegerObject((string) $difference); } @@ -71,9 +73,11 @@ final class BrickMathCalculator implements CalculatorInterface $product = BigInteger::of($multiplicand->toString()); foreach ($multipliers as $multiplier) { + /** @phpstan-ignore possiblyImpure.methodCall */ $product = $product->multipliedBy($multiplier->toString()); } + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.new */ return new IntegerObject((string) $product); } @@ -83,24 +87,29 @@ final class BrickMathCalculator implements CalculatorInterface NumberInterface $dividend, NumberInterface ...$divisors, ): NumberInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ $brickRounding = $this->getBrickRoundingMode($roundingMode); $quotient = BigDecimal::of($dividend->toString()); foreach ($divisors as $divisor) { + /** @phpstan-ignore possiblyImpure.methodCall */ $quotient = $quotient->dividedBy($divisor->toString(), $scale, $brickRounding); } if ($scale === 0) { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall, possiblyImpure.new */ return new IntegerObject((string) $quotient->toBigInteger()); } + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.new */ return new Decimal((string) $quotient); } public function fromBase(string $value, int $base): IntegerObject { try { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.new */ return new IntegerObject((string) BigInteger::fromBase($value, $base)); } catch (MathException | \InvalidArgumentException $exception) { throw new InvalidArgumentException( @@ -114,6 +123,7 @@ final class BrickMathCalculator implements CalculatorInterface public function toBase(IntegerObject $value, int $base): string { try { + /** @phpstan-ignore possiblyImpure.methodCall */ return BigInteger::of($value->toString())->toBase($base); } catch (MathException | \InvalidArgumentException $exception) { throw new InvalidArgumentException( @@ -126,6 +136,7 @@ final class BrickMathCalculator implements CalculatorInterface public function toHexadecimal(IntegerObject $value): Hexadecimal { + /** @phpstan-ignore possiblyImpure.new */ return new Hexadecimal($this->toBase($value, 16)); } diff --git a/src/Math/CalculatorInterface.php b/src/Math/CalculatorInterface.php index 57bd7a3..e6789a6 100644 --- a/src/Math/CalculatorInterface.php +++ b/src/Math/CalculatorInterface.php @@ -32,6 +32,8 @@ interface CalculatorInterface * @param NumberInterface ...$addends The additional integers to a add to the augend * * @return NumberInterface The sum of all the parameters + * + * @pure */ public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface; @@ -42,6 +44,8 @@ interface CalculatorInterface * @param NumberInterface ...$subtrahends The integers to subtract from the minuend * * @return NumberInterface The difference after subtracting all parameters + * + * @pure */ public function subtract(NumberInterface $minuend, NumberInterface ...$subtrahends): NumberInterface; @@ -52,6 +56,8 @@ interface CalculatorInterface * @param NumberInterface ...$multipliers The factors by which to multiply the multiplicand * * @return NumberInterface The product of multiplying all the provided parameters + * + * @pure */ public function multiply(NumberInterface $multiplicand, NumberInterface ...$multipliers): NumberInterface; @@ -65,6 +71,8 @@ interface CalculatorInterface * operations should take place (left-to-right) * * @return NumberInterface The quotient of dividing the provided parameters left-to-right + * + * @pure */ public function divide( int $roundingMode, @@ -80,6 +88,8 @@ interface CalculatorInterface * @param int $base The base to convert from (i.e., 2, 16, 32, etc.) * * @return IntegerObject The base-10 integer value of the converted value + * + * @pure */ public function fromBase(string $value, int $base): IntegerObject; @@ -90,16 +100,22 @@ interface CalculatorInterface * @param int $base The base to convert to (i.e., 2, 16, 32, etc.) * * @return string The value represented in the specified base + * + * @pure */ public function toBase(IntegerObject $value, int $base): string; /** * Converts an Integer instance to a Hexadecimal instance + * + * @pure */ public function toHexadecimal(IntegerObject $value): Hexadecimal; /** * Converts a Hexadecimal instance to an Integer instance + * + * @pure */ public function toInteger(Hexadecimal $value): IntegerObject; } diff --git a/src/Nonstandard/Uuid.php b/src/Nonstandard/Uuid.php index 32a2496..7f15e6e 100644 --- a/src/Nonstandard/Uuid.php +++ b/src/Nonstandard/Uuid.php @@ -23,6 +23,7 @@ use Ramsey\Uuid\Uuid as BaseUuid; * Nonstandard\Uuid is a UUID that doesn't conform to RFC 9562 (formerly RFC 4122) * * @immutable + * @pure */ final class Uuid extends BaseUuid { diff --git a/src/Nonstandard/UuidBuilder.php b/src/Nonstandard/UuidBuilder.php index a9885cb..74da992 100644 --- a/src/Nonstandard/UuidBuilder.php +++ b/src/Nonstandard/UuidBuilder.php @@ -53,17 +53,22 @@ class UuidBuilder implements UuidBuilderInterface public function build(CodecInterface $codec, string $bytes): UuidInterface { try { + /** @phpstan-ignore possiblyImpure.new */ return new Uuid($this->buildFields($bytes), $this->numberConverter, $codec, $this->timeConverter); } catch (Throwable $e) { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing + * + * @pure */ protected function buildFields(string $bytes): Fields { + /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } diff --git a/src/Rfc4122/Fields.php b/src/Rfc4122/Fields.php index 6577120..4f607d5 100644 --- a/src/Rfc4122/Fields.php +++ b/src/Rfc4122/Fields.php @@ -73,6 +73,9 @@ final class Fields implements FieldsInterface } } + /** + * @pure + */ public function getBytes(): string { return $this->bytes; diff --git a/src/Rfc4122/FieldsInterface.php b/src/Rfc4122/FieldsInterface.php index 7e17e50..13d86d9 100644 --- a/src/Rfc4122/FieldsInterface.php +++ b/src/Rfc4122/FieldsInterface.php @@ -114,6 +114,8 @@ interface FieldsInterface extends BaseFieldsInterface * meaningful for this variant. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field + * + * @pure */ public function getVersion(): ?int; @@ -121,6 +123,8 @@ interface FieldsInterface extends BaseFieldsInterface * Returns true if these fields represent a nil UUID * * The nil UUID is a special form of UUID that is specified to have all 128 bits set to zero. + * + * @pure */ public function isNil(): bool; } diff --git a/src/Rfc4122/MaxTrait.php b/src/Rfc4122/MaxTrait.php index 988b524..8646e6a 100644 --- a/src/Rfc4122/MaxTrait.php +++ b/src/Rfc4122/MaxTrait.php @@ -23,11 +23,15 @@ trait MaxTrait { /** * Returns the bytes that comprise the fields + * + * @pure */ abstract public function getBytes(): string; /** * Returns true if the byte string represents a max UUID + * + * @pure */ public function isMax(): bool { diff --git a/src/Rfc4122/NilTrait.php b/src/Rfc4122/NilTrait.php index 6461e96..19d1377 100644 --- a/src/Rfc4122/NilTrait.php +++ b/src/Rfc4122/NilTrait.php @@ -23,6 +23,8 @@ trait NilTrait { /** * Returns the bytes that comprise the fields + * + * @pure */ abstract public function getBytes(): string; diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php index 5c239c2..787a0b7 100644 --- a/src/Rfc4122/UuidBuilder.php +++ b/src/Rfc4122/UuidBuilder.php @@ -70,39 +70,53 @@ class UuidBuilder implements UuidBuilderInterface $fields = $this->buildFields($bytes); if ($fields->isNil()) { + /** @phpstan-ignore possiblyImpure.new */ return new NilUuid($fields, $this->numberConverter, $codec, $this->timeConverter); } if ($fields->isMax()) { + /** @phpstan-ignore possiblyImpure.new */ return new MaxUuid($fields, $this->numberConverter, $codec, $this->timeConverter); } return match ($fields->getVersion()) { + /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_TIME => new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_DCE_SECURITY + /** @phpstan-ignore possiblyImpure.new */ => new UuidV2($fields, $this->numberConverter, $codec, $this->timeConverter), + /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_HASH_MD5 => new UuidV3($fields, $this->numberConverter, $codec, $this->timeConverter), + /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_RANDOM => new UuidV4($fields, $this->numberConverter, $codec, $this->timeConverter), + /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_HASH_SHA1 => new UuidV5($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_REORDERED_TIME + /** @phpstan-ignore possiblyImpure.new */ => new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_UNIX_TIME + /** @phpstan-ignore possiblyImpure.new */ => new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter), + /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_CUSTOM => new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter), default => throw new UnsupportedOperationException( 'The UUID version in the given fields is not supported by this UUID builder', ), }; } catch (Throwable $e) { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing + * + * @pure */ protected function buildFields(string $bytes): FieldsInterface { + /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php index d2b7645..1736286 100644 --- a/src/Rfc4122/Validator.php +++ b/src/Rfc4122/Validator.php @@ -40,8 +40,10 @@ final class Validator implements ValidatorInterface public function validate(string $uuid): bool { + /** @phpstan-ignore possiblyImpure.functionCall */ $uuid = strtolower(str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid)); + /** @phpstan-ignore possiblyImpure.functionCall */ return $uuid === Uuid::NIL || $uuid === Uuid::MAX || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); } } diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php index 7b5ccab..5f4e17b 100644 --- a/src/Rfc4122/VersionTrait.php +++ b/src/Rfc4122/VersionTrait.php @@ -41,6 +41,8 @@ trait VersionTrait * meaningful for this variant. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field + * + * @pure */ abstract public function getVersion(): ?int; diff --git a/src/Type/Hexadecimal.php b/src/Type/Hexadecimal.php index 3883a43..c411764 100644 --- a/src/Type/Hexadecimal.php +++ b/src/Type/Hexadecimal.php @@ -46,6 +46,8 @@ final class Hexadecimal implements TypeInterface /** * @return non-empty-string + * + * @pure */ public function toString(): string { diff --git a/src/Type/Integer.php b/src/Type/Integer.php index be2dfaf..ed6c82d 100644 --- a/src/Type/Integer.php +++ b/src/Type/Integer.php @@ -58,6 +58,8 @@ final class Integer implements NumberInterface /** * @return numeric-string + * + * @pure */ public function toString(): string { diff --git a/src/Type/Time.php b/src/Type/Time.php index c475563..2556c5b 100644 --- a/src/Type/Time.php +++ b/src/Type/Time.php @@ -43,11 +43,17 @@ final class Time implements TypeInterface $this->microseconds = new IntegerObject($microseconds); } + /** + * @pure + */ public function getSeconds(): IntegerObject { return $this->seconds; } + /** + * @pure + */ public function getMicroseconds(): IntegerObject { return $this->microseconds; diff --git a/src/Type/TypeInterface.php b/src/Type/TypeInterface.php index d9a31e4..0c88a28 100644 --- a/src/Type/TypeInterface.php +++ b/src/Type/TypeInterface.php @@ -24,7 +24,13 @@ use Serializable; */ interface TypeInterface extends JsonSerializable, Serializable { + /** + * @pure + */ public function toString(): string; + /** + * @pure + */ public function __toString(): string; } diff --git a/src/Uuid.php b/src/Uuid.php index 449a789..c2bb92d 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -453,6 +453,7 @@ class Uuid implements UuidInterface */ public static function fromBytes(string $bytes): UuidInterface { + /** @phpstan-ignore impure.staticPropertyAccess */ if (!self::$factoryReplaced && strlen($bytes) === 16) { $base16Uuid = bin2hex($bytes); @@ -470,6 +471,7 @@ class Uuid implements UuidInterface ); } + /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromBytes($bytes); } @@ -487,12 +489,16 @@ class Uuid implements UuidInterface public static function fromString(string $uuid): UuidInterface { $uuid = strtolower($uuid); + /** @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.functionCall */ if (!self::$factoryReplaced && preg_match(LazyUuidFromString::VALID_REGEX, $uuid) === 1) { + /** @phpstan-ignore possiblyImpure.functionCall */ assert($uuid !== ''); + /** @phpstan-ignore possiblyImpure.new */ return new LazyUuidFromString($uuid); } + /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromString($uuid); } @@ -527,10 +533,13 @@ class Uuid implements UuidInterface */ public static function fromHexadecimal(Hexadecimal $hex): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ $factory = self::getFactory(); if (method_exists($factory, 'fromHexadecimal')) { + /** @phpstan-ignore possiblyImpure.methodCall */ $uuid = $factory->fromHexadecimal($hex); + /** @phpstan-ignore possiblyImpure.functionCall */ assert($uuid instanceof UuidInterface); return $uuid; @@ -552,6 +561,7 @@ class Uuid implements UuidInterface */ public static function fromInteger(string $integer): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromInteger($integer); } @@ -568,6 +578,7 @@ class Uuid implements UuidInterface */ public static function isValid(string $uuid): bool { + /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ return self::getFactory()->getValidator()->validate($uuid); } @@ -621,6 +632,7 @@ class Uuid implements UuidInterface */ public static function uuid3($ns, string $name): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->uuid3($ns, $name); } @@ -646,6 +658,7 @@ class Uuid implements UuidInterface */ public static function uuid5($ns, string $name): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->uuid5($ns, $name); } @@ -701,10 +714,12 @@ class Uuid implements UuidInterface */ public static function uuid8(string $bytes): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ $factory = self::getFactory(); if (method_exists($factory, 'uuid8')) { - /** @var UuidInterface */ + /** @var UuidInterface + * @phpstan-ignore possiblyImpure.methodCall */ return $factory->uuid8($bytes); } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 19be738..c7607a1 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -396,6 +396,7 @@ class UuidFactory implements UuidFactoryInterface */ public function uuid8(string $bytes): UuidInterface { + /** @phpstan-ignore possiblyImpure.methodCall */ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM); } @@ -439,6 +440,7 @@ class UuidFactory implements UuidFactoryInterface $bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm); + /** @phpstan-ignore possiblyImpure.methodCall */ return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version); } diff --git a/src/UuidInterface.php b/src/UuidInterface.php index 6960fed..38525cb 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -60,6 +60,8 @@ interface UuidInterface extends * Returns the binary string representation of the UUID * * @return non-empty-string + * + * @pure */ public function getBytes(): string; @@ -92,6 +94,8 @@ interface UuidInterface extends * Returns the string standard representation of the UUID * * @return non-empty-string + * + * @pure */ public function toString(): string; @@ -99,6 +103,8 @@ interface UuidInterface extends * Casts the UUID to the string standard representation * * @return non-empty-string + * + * @pure */ public function __toString(): string; } diff --git a/src/Validator/GenericValidator.php b/src/Validator/GenericValidator.php index 36fb56e..6d60647 100644 --- a/src/Validator/GenericValidator.php +++ b/src/Validator/GenericValidator.php @@ -41,8 +41,10 @@ final class GenericValidator implements ValidatorInterface public function validate(string $uuid): bool { + /** @phpstan-ignore possiblyImpure.functionCall */ $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); + /** @phpstan-ignore possiblyImpure.functionCall */ return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); } } diff --git a/src/Validator/ValidatorInterface.php b/src/Validator/ValidatorInterface.php index f125513..95dc8eb 100644 --- a/src/Validator/ValidatorInterface.php +++ b/src/Validator/ValidatorInterface.php @@ -34,6 +34,8 @@ interface ValidatorInterface * @param string $uuid The string to validate as a UUID * * @return bool True if the string is a valid UUID, false otherwise + * + * @pure */ public function validate(string $uuid): bool; } diff --git a/tests/Builder/FallbackBuilderTest.php b/tests/Builder/FallbackBuilderTest.php index 31b9589..1a090b2 100644 --- a/tests/Builder/FallbackBuilderTest.php +++ b/tests/Builder/FallbackBuilderTest.php @@ -58,6 +58,7 @@ class FallbackBuilderTest extends TestCase 'Could not find a suitable builder for the provided codec and fields' ); + /** @phpstan-ignore method.resultUnused */ $fallbackBuilder->build($codec, $bytes); } diff --git a/tests/Codec/GuidStringCodecTest.php b/tests/Codec/GuidStringCodecTest.php index 4394586..19f7261 100644 --- a/tests/Codec/GuidStringCodecTest.php +++ b/tests/Codec/GuidStringCodecTest.php @@ -56,6 +56,7 @@ class GuidStringCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new GuidStringCodec($this->builder); + /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } diff --git a/tests/Codec/OrderedTimeCodecTest.php b/tests/Codec/OrderedTimeCodecTest.php index a0341ab..c42a1d9 100644 --- a/tests/Codec/OrderedTimeCodecTest.php +++ b/tests/Codec/OrderedTimeCodecTest.php @@ -77,6 +77,7 @@ class OrderedTimeCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new OrderedTimeCodec($this->builder); + /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } @@ -165,6 +166,7 @@ class OrderedTimeCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected version 1 (time-based) UUID'); + /** @phpstan-ignore method.resultUnused */ $codec->encodeBinary($uuid); } @@ -185,6 +187,7 @@ class OrderedTimeCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected version 1 (time-based) UUID'); + /** @phpstan-ignore method.resultUnused */ $codec->encodeBinary($uuid); } diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php index 2412dcd..b38a435 100644 --- a/tests/Codec/StringCodecTest.php +++ b/tests/Codec/StringCodecTest.php @@ -60,6 +60,7 @@ class StringCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new StringCodec($this->builder); + /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } @@ -135,6 +136,7 @@ class StringCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$bytes string should contain 16 characters.'); + /** @phpstan-ignore method.resultUnused */ $codec->decodeBytes($bytes); } diff --git a/tests/Converter/Number/BigNumberConverterTest.php b/tests/Converter/Number/BigNumberConverterTest.php index 83bcff2..c3dc6d4 100644 --- a/tests/Converter/Number/BigNumberConverterTest.php +++ b/tests/Converter/Number/BigNumberConverterTest.php @@ -17,6 +17,7 @@ class BigNumberConverterTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('"." is not a valid character in base 16'); + /** @phpstan-ignore method.resultUnused */ $converter->fromHex('123.34'); } @@ -30,6 +31,7 @@ class BigNumberConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); + /** @phpstan-ignore method.resultUnused */ $converter->toHex('123.34'); } diff --git a/tests/Converter/Time/BigNumberTimeConverterTest.php b/tests/Converter/Time/BigNumberTimeConverterTest.php index f5acc98..235e878 100644 --- a/tests/Converter/Time/BigNumberTimeConverterTest.php +++ b/tests/Converter/Time/BigNumberTimeConverterTest.php @@ -56,6 +56,7 @@ class BigNumberTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); + /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('12.34', '5678'); } @@ -69,6 +70,7 @@ class BigNumberTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); + /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('1234', '56.78'); } } diff --git a/tests/Converter/Time/PhpTimeConverterTest.php b/tests/Converter/Time/PhpTimeConverterTest.php index 2036fdd..4fa62cc 100644 --- a/tests/Converter/Time/PhpTimeConverterTest.php +++ b/tests/Converter/Time/PhpTimeConverterTest.php @@ -52,6 +52,7 @@ class PhpTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); + /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('12.34', '5678'); } @@ -66,6 +67,7 @@ class PhpTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); + /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('1234', '56.78'); } diff --git a/tests/Encoder/TimestampFirstCombCodecTest.php b/tests/Encoder/TimestampFirstCombCodecTest.php index 875695f..fd5e53a 100644 --- a/tests/Encoder/TimestampFirstCombCodecTest.php +++ b/tests/Encoder/TimestampFirstCombCodecTest.php @@ -75,6 +75,7 @@ class TimestampFirstCombCodecTest extends TestCase 'node' => '0800200c9a66', ])) ); + /** @phpstan-ignore method.resultUnused */ $this->codec->decode('0800200c-9a66-11e1-9b21-ff6f8cb0c57d'); } diff --git a/tests/Encoder/TimestampLastCombCodecTest.php b/tests/Encoder/TimestampLastCombCodecTest.php index 5bd41c2..8099602 100644 --- a/tests/Encoder/TimestampLastCombCodecTest.php +++ b/tests/Encoder/TimestampLastCombCodecTest.php @@ -78,6 +78,7 @@ class TimestampLastCombCodecTest extends TestCase 'node' => 'ff6f8cb0c57d', ])) ); + /** @phpstan-ignore method.resultUnused */ $this->codec->decode('0800200c-9a66-11e1-9b21-ff6f8cb0c57d'); } diff --git a/tests/Generator/DefaultNameGeneratorTest.php b/tests/Generator/DefaultNameGeneratorTest.php index 9bfb556..b49b771 100644 --- a/tests/Generator/DefaultNameGeneratorTest.php +++ b/tests/Generator/DefaultNameGeneratorTest.php @@ -79,6 +79,7 @@ class DefaultNameGeneratorTest extends TestCase 'Unable to hash namespace and name with algorithm \'aBadAlgorithm\'' ); + /** @phpstan-ignore method.resultUnused */ $generator->generate($namespace, 'a test name', 'aBadAlgorithm'); } } diff --git a/tests/Generator/PeclUuidNameGeneratorTest.php b/tests/Generator/PeclUuidNameGeneratorTest.php index 0bd91d3..4bbbf31 100644 --- a/tests/Generator/PeclUuidNameGeneratorTest.php +++ b/tests/Generator/PeclUuidNameGeneratorTest.php @@ -99,6 +99,7 @@ class PeclUuidNameGeneratorTest extends TestCase 'Unable to hash namespace and name with algorithm \'aBadAlgorithm\'' ); + /** @phpstan-ignore method.resultUnused */ $generator->generate($namespace, 'a test name', 'aBadAlgorithm'); } } diff --git a/tests/Guid/GuidBuilderTest.php b/tests/Guid/GuidBuilderTest.php index df0405a..d3279f3 100644 --- a/tests/Guid/GuidBuilderTest.php +++ b/tests/Guid/GuidBuilderTest.php @@ -28,6 +28,7 @@ class GuidBuilderTest extends TestCase $this->expectException(UnableToBuildUuidException::class); $this->expectExceptionMessage('exception thrown'); + /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/Math/BrickMathCalculatorTest.php b/tests/Math/BrickMathCalculatorTest.php index 8cb5d90..02dcec9 100644 --- a/tests/Math/BrickMathCalculatorTest.php +++ b/tests/Math/BrickMathCalculatorTest.php @@ -98,6 +98,7 @@ class BrickMathCalculatorTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('"o" is not a valid character in base 16'); + /** @phpstan-ignore method.resultUnused */ $calculator->fromBase('foobar', 16); } diff --git a/tests/Nonstandard/UuidBuilderTest.php b/tests/Nonstandard/UuidBuilderTest.php index 7bf36a9..f77512c 100644 --- a/tests/Nonstandard/UuidBuilderTest.php +++ b/tests/Nonstandard/UuidBuilderTest.php @@ -28,6 +28,7 @@ class UuidBuilderTest extends TestCase $this->expectException(UnableToBuildUuidException::class); $this->expectExceptionMessage('exception thrown'); + /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php index 9e53487..ca00442 100644 --- a/tests/Rfc4122/UuidBuilderTest.php +++ b/tests/Rfc4122/UuidBuilderTest.php @@ -140,6 +140,7 @@ class UuidBuilderTest extends TestCase 'The byte string must be 16 bytes long; received 15 bytes' ); + /** @phpstan-ignore method.resultUnused */ $builder->build($codec, $bytes); } @@ -163,6 +164,7 @@ class UuidBuilderTest extends TestCase 'The UUID version in the given fields is not supported by this UUID builder' ); + /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 153cffd..415b0c3 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -861,6 +861,7 @@ class UuidTest extends TestCase $this->expectException(UnsupportedOperationException::class); $this->expectExceptionMessage('The provided factory does not support the uuid8() method'); + /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"); } @@ -1743,6 +1744,7 @@ class UuidTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid UUID string:'); + /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid3('', ''); } @@ -1765,6 +1767,7 @@ class UuidTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid UUID string:'); + /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid5('', ''); } diff --git a/tests/benchmark/GuidConversionBench.php b/tests/benchmark/GuidConversionBench.php index a11842a..5c8f5ed 100644 --- a/tests/benchmark/GuidConversionBench.php +++ b/tests/benchmark/GuidConversionBench.php @@ -38,6 +38,7 @@ final class GuidConversionBench public function benchStringConversionOfGuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } } diff --git a/tests/benchmark/NonLazyUuidConversionBench.php b/tests/benchmark/NonLazyUuidConversionBench.php index 32d0e66..75b4adc 100644 --- a/tests/benchmark/NonLazyUuidConversionBench.php +++ b/tests/benchmark/NonLazyUuidConversionBench.php @@ -34,6 +34,7 @@ final class NonLazyUuidConversionBench public function benchStringConversionOfUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } } diff --git a/tests/benchmark/UuidGenerationBench.php b/tests/benchmark/UuidGenerationBench.php index b474993..1992dfe 100644 --- a/tests/benchmark/UuidGenerationBench.php +++ b/tests/benchmark/UuidGenerationBench.php @@ -73,6 +73,7 @@ final class UuidGenerationBench public function benchUuid3Generation(): void { + /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid3($this->namespace, 'name'); } @@ -83,6 +84,7 @@ final class UuidGenerationBench public function benchUuid5Generation(): void { + /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid5($this->namespace, 'name'); } diff --git a/tests/benchmark/UuidStringConversionBench.php b/tests/benchmark/UuidStringConversionBench.php index d7c098c..3693d2b 100644 --- a/tests/benchmark/UuidStringConversionBench.php +++ b/tests/benchmark/UuidStringConversionBench.php @@ -208,16 +208,19 @@ final class UuidStringConversionBench public function benchStringConversionOfTinyUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->tinyUuid->toString(); } public function benchStringConversionOfHugeUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->hugeUuid->toString(); } public function benchStringConversionOfUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } @@ -230,16 +233,19 @@ final class UuidStringConversionBench public function benchBytesConversionOfTinyUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->tinyUuid->getBytes(); } public function benchBytesConversionOfHugeUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->hugeUuid->getBytes(); } public function benchBytesConversionOfUuid(): void { + /** @phpstan-ignore method.resultUnused */ $this->uuid->getBytes(); } From 088b87356d82535787ffc9eafce21cbdb8c983cc Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Tue, 24 Jun 2025 20:09:34 -0500 Subject: [PATCH 14/17] Use explicit error identifiers when ignoring PHPStan errors --- .../Number/GenericNumberConverter.php | 2 +- src/Converter/Time/GenericTimeConverter.php | 19 +++++++++++++------ src/Converter/Time/UnixTimeConverter.php | 2 +- src/Lazy/LazyUuidFromString.php | 6 ++++-- src/Uuid.php | 6 ++++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Converter/Number/GenericNumberConverter.php b/src/Converter/Number/GenericNumberConverter.php index dcbc132..86968ab 100644 --- a/src/Converter/Number/GenericNumberConverter.php +++ b/src/Converter/Number/GenericNumberConverter.php @@ -42,7 +42,7 @@ class GenericNumberConverter implements NumberConverterInterface */ public function toHex(string $number): string { - /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ + /** @phpstan-ignore return.type, possiblyImpure.new */ return $this->calculator->toBase(new IntegerObject($number), 16); } } diff --git a/src/Converter/Time/GenericTimeConverter.php b/src/Converter/Time/GenericTimeConverter.php index d0dd06c..1079e88 100644 --- a/src/Converter/Time/GenericTimeConverter.php +++ b/src/Converter/Time/GenericTimeConverter.php @@ -69,14 +69,21 @@ class GenericTimeConverter implements TimeConverterInterface new IntegerObject(self::MICROSECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); - // Combine the intervals of seconds and microseconds and add the count of 100-nanosecond intervals from the - // Gregorian calendar epoch to the Unix epoch. This gives us the correct count of 100-nanosecond intervals since - // the Gregorian calendar epoch for the given seconds and microseconds. - /** @var IntegerObject $uuidTime */ - /** @phpstan-ignore possiblyImpure.new */ + /** + * Combine the intervals of seconds and microseconds and add the count of 100-nanosecond intervals from the + * Gregorian calendar epoch to the Unix epoch. This gives us the correct count of 100-nanosecond intervals since + * the Gregorian calendar epoch for the given seconds and microseconds. + * + * @var IntegerObject $uuidTime + * @phpstan-ignore possiblyImpure.new + */ $uuidTime = $this->calculator->add($sec, $usec, new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)); - /** @phpstan-ignore-next-line phpstan considers CalculatorInterface::toHexidecimal, Hexadecimal:toString impure */ + /** + * PHPStan considers CalculatorInterface::toHexadecimal, Hexadecimal:toString impure. + * + * @phpstan-ignore possiblyImpure.new + */ return new Hexadecimal(str_pad($this->calculator->toHexadecimal($uuidTime)->toString(), 16, '0', STR_PAD_LEFT)); } diff --git a/src/Converter/Time/UnixTimeConverter.php b/src/Converter/Time/UnixTimeConverter.php index 843efb7..4bd4125 100644 --- a/src/Converter/Time/UnixTimeConverter.php +++ b/src/Converter/Time/UnixTimeConverter.php @@ -69,7 +69,7 @@ class UnixTimeConverter implements TimeConverterInterface 12, '0', STR_PAD_LEFT - ) + ), ); } diff --git a/src/Lazy/LazyUuidFromString.php b/src/Lazy/LazyUuidFromString.php index 372762a..8d3129c 100644 --- a/src/Lazy/LazyUuidFromString.php +++ b/src/Lazy/LazyUuidFromString.php @@ -214,8 +214,10 @@ final class LazyUuidFromString implements UuidInterface public function getBytes(): string { - /** @var non-empty-string - * @phpstan-ignore-next-line Avoiding pure function complaints */ + /** + * @var non-empty-string + * @phpstan-ignore possiblyImpure.functionCall, possiblyImpure.functionCall + */ return (string) hex2bin(str_replace('-', '', $this->uuid)); } diff --git a/src/Uuid.php b/src/Uuid.php index c2bb92d..0f05bbf 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -718,8 +718,10 @@ class Uuid implements UuidInterface $factory = self::getFactory(); if (method_exists($factory, 'uuid8')) { - /** @var UuidInterface - * @phpstan-ignore possiblyImpure.methodCall */ + /** + * @var UuidInterface + * @phpstan-ignore possiblyImpure.methodCall + */ return $factory->uuid8($bytes); } From 4ca249e960afc26654802c10c2eb036b7a034702 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Tue, 24 Jun 2025 20:23:23 -0500 Subject: [PATCH 15/17] Ignore the "result unused" error in tests from the PHPStan config --- phpstan.neon.dist | 7 +++++++ tests/Builder/FallbackBuilderTest.php | 1 - tests/Codec/GuidStringCodecTest.php | 1 - tests/Codec/OrderedTimeCodecTest.php | 3 --- tests/Codec/StringCodecTest.php | 2 -- tests/Converter/Number/BigNumberConverterTest.php | 2 -- tests/Converter/Time/BigNumberTimeConverterTest.php | 2 -- tests/Converter/Time/PhpTimeConverterTest.php | 2 -- tests/Encoder/TimestampFirstCombCodecTest.php | 1 - tests/Encoder/TimestampLastCombCodecTest.php | 1 - tests/Generator/DefaultNameGeneratorTest.php | 1 - tests/Generator/PeclUuidNameGeneratorTest.php | 1 - tests/Guid/GuidBuilderTest.php | 1 - tests/Math/BrickMathCalculatorTest.php | 1 - tests/Nonstandard/UuidBuilderTest.php | 1 - tests/Rfc4122/UuidBuilderTest.php | 2 -- tests/benchmark/GuidConversionBench.php | 1 - tests/benchmark/NonLazyUuidConversionBench.php | 1 - tests/benchmark/UuidGenerationBench.php | 2 -- tests/benchmark/UuidStringConversionBench.php | 6 ------ 20 files changed, 7 insertions(+), 32 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4afc863..87969bf 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -11,3 +11,10 @@ parameters: analyse: - ./tests/ExpectedBehaviorTest.php - ./tests/static-analysis/stubs.php + ignoreErrors: + - + identifier: method.resultUnused + path: tests/* + - + identifier: staticMethod.resultUnused + path: tests/* diff --git a/tests/Builder/FallbackBuilderTest.php b/tests/Builder/FallbackBuilderTest.php index 1a090b2..31b9589 100644 --- a/tests/Builder/FallbackBuilderTest.php +++ b/tests/Builder/FallbackBuilderTest.php @@ -58,7 +58,6 @@ class FallbackBuilderTest extends TestCase 'Could not find a suitable builder for the provided codec and fields' ); - /** @phpstan-ignore method.resultUnused */ $fallbackBuilder->build($codec, $bytes); } diff --git a/tests/Codec/GuidStringCodecTest.php b/tests/Codec/GuidStringCodecTest.php index 19f7261..4394586 100644 --- a/tests/Codec/GuidStringCodecTest.php +++ b/tests/Codec/GuidStringCodecTest.php @@ -56,7 +56,6 @@ class GuidStringCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new GuidStringCodec($this->builder); - /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } diff --git a/tests/Codec/OrderedTimeCodecTest.php b/tests/Codec/OrderedTimeCodecTest.php index c42a1d9..a0341ab 100644 --- a/tests/Codec/OrderedTimeCodecTest.php +++ b/tests/Codec/OrderedTimeCodecTest.php @@ -77,7 +77,6 @@ class OrderedTimeCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new OrderedTimeCodec($this->builder); - /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } @@ -166,7 +165,6 @@ class OrderedTimeCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected version 1 (time-based) UUID'); - /** @phpstan-ignore method.resultUnused */ $codec->encodeBinary($uuid); } @@ -187,7 +185,6 @@ class OrderedTimeCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected version 1 (time-based) UUID'); - /** @phpstan-ignore method.resultUnused */ $codec->encodeBinary($uuid); } diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php index b38a435..2412dcd 100644 --- a/tests/Codec/StringCodecTest.php +++ b/tests/Codec/StringCodecTest.php @@ -60,7 +60,6 @@ class StringCodecTest extends TestCase ->method('getFields') ->willReturn($this->fields); $codec = new StringCodec($this->builder); - /** @phpstan-ignore method.resultUnused */ $codec->encode($this->uuid); } @@ -136,7 +135,6 @@ class StringCodecTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$bytes string should contain 16 characters.'); - /** @phpstan-ignore method.resultUnused */ $codec->decodeBytes($bytes); } diff --git a/tests/Converter/Number/BigNumberConverterTest.php b/tests/Converter/Number/BigNumberConverterTest.php index c3dc6d4..83bcff2 100644 --- a/tests/Converter/Number/BigNumberConverterTest.php +++ b/tests/Converter/Number/BigNumberConverterTest.php @@ -17,7 +17,6 @@ class BigNumberConverterTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('"." is not a valid character in base 16'); - /** @phpstan-ignore method.resultUnused */ $converter->fromHex('123.34'); } @@ -31,7 +30,6 @@ class BigNumberConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); - /** @phpstan-ignore method.resultUnused */ $converter->toHex('123.34'); } diff --git a/tests/Converter/Time/BigNumberTimeConverterTest.php b/tests/Converter/Time/BigNumberTimeConverterTest.php index 235e878..f5acc98 100644 --- a/tests/Converter/Time/BigNumberTimeConverterTest.php +++ b/tests/Converter/Time/BigNumberTimeConverterTest.php @@ -56,7 +56,6 @@ class BigNumberTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); - /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('12.34', '5678'); } @@ -70,7 +69,6 @@ class BigNumberTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); - /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('1234', '56.78'); } } diff --git a/tests/Converter/Time/PhpTimeConverterTest.php b/tests/Converter/Time/PhpTimeConverterTest.php index 4fa62cc..2036fdd 100644 --- a/tests/Converter/Time/PhpTimeConverterTest.php +++ b/tests/Converter/Time/PhpTimeConverterTest.php @@ -52,7 +52,6 @@ class PhpTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); - /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('12.34', '5678'); } @@ -67,7 +66,6 @@ class PhpTimeConverterTest extends TestCase . '0-9 and, optionally, a sign (+ or -)' ); - /** @phpstan-ignore method.resultUnused */ $converter->calculateTime('1234', '56.78'); } diff --git a/tests/Encoder/TimestampFirstCombCodecTest.php b/tests/Encoder/TimestampFirstCombCodecTest.php index fd5e53a..875695f 100644 --- a/tests/Encoder/TimestampFirstCombCodecTest.php +++ b/tests/Encoder/TimestampFirstCombCodecTest.php @@ -75,7 +75,6 @@ class TimestampFirstCombCodecTest extends TestCase 'node' => '0800200c9a66', ])) ); - /** @phpstan-ignore method.resultUnused */ $this->codec->decode('0800200c-9a66-11e1-9b21-ff6f8cb0c57d'); } diff --git a/tests/Encoder/TimestampLastCombCodecTest.php b/tests/Encoder/TimestampLastCombCodecTest.php index 8099602..5bd41c2 100644 --- a/tests/Encoder/TimestampLastCombCodecTest.php +++ b/tests/Encoder/TimestampLastCombCodecTest.php @@ -78,7 +78,6 @@ class TimestampLastCombCodecTest extends TestCase 'node' => 'ff6f8cb0c57d', ])) ); - /** @phpstan-ignore method.resultUnused */ $this->codec->decode('0800200c-9a66-11e1-9b21-ff6f8cb0c57d'); } diff --git a/tests/Generator/DefaultNameGeneratorTest.php b/tests/Generator/DefaultNameGeneratorTest.php index b49b771..9bfb556 100644 --- a/tests/Generator/DefaultNameGeneratorTest.php +++ b/tests/Generator/DefaultNameGeneratorTest.php @@ -79,7 +79,6 @@ class DefaultNameGeneratorTest extends TestCase 'Unable to hash namespace and name with algorithm \'aBadAlgorithm\'' ); - /** @phpstan-ignore method.resultUnused */ $generator->generate($namespace, 'a test name', 'aBadAlgorithm'); } } diff --git a/tests/Generator/PeclUuidNameGeneratorTest.php b/tests/Generator/PeclUuidNameGeneratorTest.php index 4bbbf31..0bd91d3 100644 --- a/tests/Generator/PeclUuidNameGeneratorTest.php +++ b/tests/Generator/PeclUuidNameGeneratorTest.php @@ -99,7 +99,6 @@ class PeclUuidNameGeneratorTest extends TestCase 'Unable to hash namespace and name with algorithm \'aBadAlgorithm\'' ); - /** @phpstan-ignore method.resultUnused */ $generator->generate($namespace, 'a test name', 'aBadAlgorithm'); } } diff --git a/tests/Guid/GuidBuilderTest.php b/tests/Guid/GuidBuilderTest.php index d3279f3..df0405a 100644 --- a/tests/Guid/GuidBuilderTest.php +++ b/tests/Guid/GuidBuilderTest.php @@ -28,7 +28,6 @@ class GuidBuilderTest extends TestCase $this->expectException(UnableToBuildUuidException::class); $this->expectExceptionMessage('exception thrown'); - /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/Math/BrickMathCalculatorTest.php b/tests/Math/BrickMathCalculatorTest.php index 02dcec9..8cb5d90 100644 --- a/tests/Math/BrickMathCalculatorTest.php +++ b/tests/Math/BrickMathCalculatorTest.php @@ -98,7 +98,6 @@ class BrickMathCalculatorTest extends TestCase $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('"o" is not a valid character in base 16'); - /** @phpstan-ignore method.resultUnused */ $calculator->fromBase('foobar', 16); } diff --git a/tests/Nonstandard/UuidBuilderTest.php b/tests/Nonstandard/UuidBuilderTest.php index f77512c..7bf36a9 100644 --- a/tests/Nonstandard/UuidBuilderTest.php +++ b/tests/Nonstandard/UuidBuilderTest.php @@ -28,7 +28,6 @@ class UuidBuilderTest extends TestCase $this->expectException(UnableToBuildUuidException::class); $this->expectExceptionMessage('exception thrown'); - /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php index ca00442..9e53487 100644 --- a/tests/Rfc4122/UuidBuilderTest.php +++ b/tests/Rfc4122/UuidBuilderTest.php @@ -140,7 +140,6 @@ class UuidBuilderTest extends TestCase 'The byte string must be 16 bytes long; received 15 bytes' ); - /** @phpstan-ignore method.resultUnused */ $builder->build($codec, $bytes); } @@ -164,7 +163,6 @@ class UuidBuilderTest extends TestCase 'The UUID version in the given fields is not supported by this UUID builder' ); - /** @phpstan-ignore method.resultUnused */ $builder->build($codec, 'foobar'); } } diff --git a/tests/benchmark/GuidConversionBench.php b/tests/benchmark/GuidConversionBench.php index 5c8f5ed..a11842a 100644 --- a/tests/benchmark/GuidConversionBench.php +++ b/tests/benchmark/GuidConversionBench.php @@ -38,7 +38,6 @@ final class GuidConversionBench public function benchStringConversionOfGuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } } diff --git a/tests/benchmark/NonLazyUuidConversionBench.php b/tests/benchmark/NonLazyUuidConversionBench.php index 75b4adc..32d0e66 100644 --- a/tests/benchmark/NonLazyUuidConversionBench.php +++ b/tests/benchmark/NonLazyUuidConversionBench.php @@ -34,7 +34,6 @@ final class NonLazyUuidConversionBench public function benchStringConversionOfUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } } diff --git a/tests/benchmark/UuidGenerationBench.php b/tests/benchmark/UuidGenerationBench.php index 1992dfe..b474993 100644 --- a/tests/benchmark/UuidGenerationBench.php +++ b/tests/benchmark/UuidGenerationBench.php @@ -73,7 +73,6 @@ final class UuidGenerationBench public function benchUuid3Generation(): void { - /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid3($this->namespace, 'name'); } @@ -84,7 +83,6 @@ final class UuidGenerationBench public function benchUuid5Generation(): void { - /** @phpstan-ignore staticMethod.resultUnused */ Uuid::uuid5($this->namespace, 'name'); } diff --git a/tests/benchmark/UuidStringConversionBench.php b/tests/benchmark/UuidStringConversionBench.php index 3693d2b..d7c098c 100644 --- a/tests/benchmark/UuidStringConversionBench.php +++ b/tests/benchmark/UuidStringConversionBench.php @@ -208,19 +208,16 @@ final class UuidStringConversionBench public function benchStringConversionOfTinyUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->tinyUuid->toString(); } public function benchStringConversionOfHugeUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->hugeUuid->toString(); } public function benchStringConversionOfUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->uuid->toString(); } @@ -233,19 +230,16 @@ final class UuidStringConversionBench public function benchBytesConversionOfTinyUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->tinyUuid->getBytes(); } public function benchBytesConversionOfHugeUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->hugeUuid->getBytes(); } public function benchBytesConversionOfUuid(): void { - /** @phpstan-ignore method.resultUnused */ $this->uuid->getBytes(); } From 1fffdc32f10f5b7af9bc848768011ca8ed6bd09d Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Wed, 25 Jun 2025 08:18:24 -0500 Subject: [PATCH 16/17] Call getFields() only once --- src/Codec/OrderedTimeCodec.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Codec/OrderedTimeCodec.php b/src/Codec/OrderedTimeCodec.php index f24f71b..ea533d9 100644 --- a/src/Codec/OrderedTimeCodec.php +++ b/src/Codec/OrderedTimeCodec.php @@ -87,12 +87,10 @@ class OrderedTimeCodec extends StringCodec $uuid = parent::decodeBytes($rearrangedBytes); - if ( - /** @phpstan-ignore possiblyImpure.methodCall */ - !($uuid->getFields() instanceof Rfc4122FieldsInterface) - /** @phpstan-ignore possiblyImpure.methodCall */ - || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME - ) { + /** @phpstan-ignore possiblyImpure.methodCall */ + $fields = $uuid->getFields(); + + if (!$fields instanceof Rfc4122FieldsInterface || $fields->getVersion() !== Uuid::UUID_TYPE_TIME) { throw new UnsupportedOperationException( 'Attempting to decode a non-time-based UUID using OrderedTimeCodec', ); From 4e0e23cc785f0724a0e838279a9eb03f28b092a0 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Wed, 25 Jun 2025 09:20:11 -0500 Subject: [PATCH 17/17] Prepare release 4.9.0 --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e578a8..8fa79e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,40 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 4.9.0 - 2025-06-25 + +### Added + +* Add new `@pure` annotations to the following ([#605](https://github.com/ramsey/uuid/pull/605)): + * `Ramsey\Uuid\Codec\CodecInterface::encode()` + * `Ramsey\Uuid\Codec\CodecInterface::encodeBinary()` + * `Ramsey\Uuid\Codec\CodecInterface::decode()` + * `Ramsey\Uuid\Codec\CodecInterface::decodeBytes()` + * `Ramsey\Uuid\Fields\FieldsInterface::getBytes()` + * `Ramsey\Uuid\Math\CalculatorInterface::add()` + * `Ramsey\Uuid\Math\CalculatorInterface::subtract()` + * `Ramsey\Uuid\Math\CalculatorInterface::multiply()` + * `Ramsey\Uuid\Math\CalculatorInterface::divide()` + * `Ramsey\Uuid\Math\CalculatorInterface::fromBase()` + * `Ramsey\Uuid\Math\CalculatorInterface::toBase()` + * `Ramsey\Uuid\Math\CalculatorInterface::toHexadecimal()` + * `Ramsey\Uuid\Math\CalculatorInterface::toInteger()` + * `Ramsey\Uuid\Nonstandard\Uuid` + * `Ramsey\Uuid\Rfc4122\Fields::isMax()` + * `Ramsey\Uuid\Rfc4122\FieldsInterface::getVersion()` + * `Ramsey\Uuid\Rfc4122\FieldsInterface::isNil()` + * `Ramsey\Uuid\Type\Time::getSeconds()` + * `Ramsey\Uuid\Type\Time::getMicroseconds()` + * `Ramsey\Uuid\Type\TypeInterface::toString()` + * `Ramsey\Uuid\UuidInterface::getBytes()` + * `Ramsey\Uuid\UuidInterface::toString()` + * `Ramsey\Uuid\Validator\ValidatorInterface::validate()` + +### Fixed + +* Restore the `@pure` annotations that were removed in 4.8.0 ([#603](https://github.com/ramsey/uuid/pull/603)). + + ## 4.8.1 - 2025-06-01 ### Fixed