From 4775f35b2d70865807c89d32c8e7385b86eb0ace Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 7 Mar 2024 16:38:35 +0100 Subject: [PATCH] Fix bug in Preg::replaceCallbackStrictGroups not detecting null values when used with PREG_OFFSET_CAPTURE --- phpstan-baseline.neon | 5 ----- src/Preg.php | 8 +++++--- tests/PregTests/ReplaceCallbackTest.php | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 46f31a5..0a3991a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,11 +5,6 @@ parameters: count: 1 path: src/Preg.php - - - message: "#^Parameter \\#2 \\$matches of static method Composer\\\\Pcre\\\\Preg\\:\\:enforceNonNullMatches\\(\\) expects array\\, array\\\\|string\\|null\\> given\\.$#" - count: 1 - path: src/Preg.php - - message: "#^Parameter &\\$matches @param\\-out type of method Composer\\\\Pcre\\\\Preg\\:\\:match\\(\\) expects array\\, \\(int is int \\? array\\\\|string\\>\\> \\: \\(int is int \\? array\\ \\: \\(int is int \\? array\\\\> \\: array\\\\)\\)\\) given\\.$#" count: 1 diff --git a/src/Preg.php b/src/Preg.php index e0c2844..71ed46e 100644 --- a/src/Preg.php +++ b/src/Preg.php @@ -391,16 +391,18 @@ private static function checkSetOrder(int $flags): void } /** - * @param array $matches + * @param array $matches * @return array * @throws UnexpectedNullMatchException */ private static function enforceNonNullMatches(string $pattern, array $matches, string $variantMethod) { foreach ($matches as $group => $match) { - if (null === $match) { - throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.'); + if (is_string($match) || (is_array($match) && is_string($match[0]))) { + continue; } + + throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.'); } /** @var array */ diff --git a/tests/PregTests/ReplaceCallbackTest.php b/tests/PregTests/ReplaceCallbackTest.php index b8c29f5..07e9bb3 100644 --- a/tests/PregTests/ReplaceCallbackTest.php +++ b/tests/PregTests/ReplaceCallbackTest.php @@ -81,6 +81,26 @@ public function testFailStrictGroups(): void }, '123', -1, $count); } + public function testSuccessStrictGroupsOffsets(): void + { + $result = Preg::replaceCallbackStrictGroups('{(?P\d)(?a)?}', function ($match) { + return strtoupper($match['matched'][0]); + }, '3a', -1, $count, PREG_OFFSET_CAPTURE); + + self::assertSame(1, $count); + self::assertSame('A', $result); + } + + public function testFailsStrictGroupsOffsets(): void + { + self::expectException(UnexpectedNullMatchException::class); + self::expectExceptionMessage('Pattern "{(?P\d)(?a)?}" had an unexpected unmatched group "unmatched", make sure the pattern always matches or use replaceCallback() instead.'); + + $result = Preg::replaceCallbackStrictGroups('{(?P\d)(?a)?}', function ($match) { + return strtoupper($match['unmatched'][0]); + }, '3', -1, $count, PREG_OFFSET_CAPTURE); + } + public function testBadPatternThrowsIfWarningsAreNotThrowing(): void { $this->expectPcreException($pattern = '{(?Pd)');