Skip to content

Commit ef4bfa7

Browse files
bug #637 [Php83][Php85][Grapheme] Throw ValueError on PHP 7 for functions that never returned false (nicolas-grekas)
This PR was merged into the 1.x branch. Discussion ---------- [Php83][Php85][Grapheme] Throw ValueError on PHP 7 for functions that never returned false | Q | A | ------------- | --- | Branch? | 1.x | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #636 | License | MIT `grapheme_levenshtein()` (8.5), `grapheme_str_split()` (8.4), `json_validate()`, `str_increment()` and `str_decrement()` (8.3) throw a `ValueError` for invalid arguments. Unlike the mbstring family, these functions were never designed to return `false`, so the polyfills should reproduce the exception on every supported PHP version. On PHP < 8 they either returned `false` (grapheme) or referenced the missing `ValueError` class, which fatals unless `polyfill-php80` happens to be installed (the case reported in #636). Each affected bootstrap now declares a guarded `ValueError` stub on PHP < 8, the same way the Apcu polyfill declares `APCuIterator`, and the functions throw on all versions. The mbstring functions (including `mb_str_pad`) keep their `trigger_error()` + `false` behavior on PHP < 8, which matches how the extension behaves there. Commits ------- c7304c2 [Php83][Php85][Grapheme] Throw ValueError on PHP 7 for functions that never returned false
2 parents 6d83660 + c7304c2 commit ef4bfa7

6 files changed

Lines changed: 49 additions & 10 deletions

File tree

src/Intl/Grapheme/Grapheme.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,6 @@ public static function grapheme_strstr($s, $needle, $beforeNeedle = false)
197197
public static function grapheme_str_split($s, $len = 1)
198198
{
199199
if (0 > $len || 1073741823 < $len) {
200-
if (80000 > \PHP_VERSION_ID) {
201-
return false;
202-
}
203-
204200
throw new \ValueError('grapheme_str_split(): Argument #2 ($length) must be greater than 0 and less than or equal to 1073741823.');
205201
}
206202

@@ -232,10 +228,6 @@ public static function grapheme_levenshtein($s1, $s2, $insertion_cost = 1, $repl
232228
}
233229

234230
if (0 > $insertion_cost || 0 > $replacement_cost || 0 > $deletion_cost) {
235-
if (80000 > \PHP_VERSION_ID) {
236-
return false;
237-
}
238-
239231
throw new \ValueError('grapheme_levenshtein(): Argument #3 ($insertion_cost), #4 ($replacement_cost), and #5 ($deletion_cost) must be greater than or equal to 0');
240232
}
241233

src/Intl/Grapheme/bootstrap.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
return require __DIR__.'/bootstrap80.php';
1616
}
1717

18+
if (!class_exists('ValueError', false)) {
19+
class ValueError extends Error
20+
{
21+
}
22+
}
23+
1824
if (!defined('GRAPHEME_EXTR_COUNT')) {
1925
define('GRAPHEME_EXTR_COUNT', 0);
2026
}

src/Php83/bootstrap72.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@
1111

1212
use Symfony\Polyfill\Php83 as p;
1313

14+
if (!class_exists('ValueError', false)) {
15+
class ValueError extends Error
16+
{
17+
}
18+
}
19+
1420
if (extension_loaded('mbstring')) {
1521
if (!function_exists('mb_str_pad')) {
1622
/** @return string|false */

src/Php85/bootstrap.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ function locale_is_right_to_left(string $locale): bool { return p\Php85::locale_
4141
return;
4242
}
4343

44+
if (!class_exists('ValueError', false)) {
45+
class ValueError extends Error
46+
{
47+
}
48+
}
49+
4450
if (extension_loaded('intl') && !function_exists('grapheme_levenshtein')) {
4551
function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1, string $locale = '') { return p\Php85::grapheme_levenshtein($string1, $string2, $insertion_cost, $replacement_cost, $deletion_cost); }
4652
}

tests/Intl/Grapheme/GraphemeTest.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,16 @@ public function testGraphemeStrSplit(string $string, int $length, array $expecte
218218
$this->assertSame($expectedValues, grapheme_str_split($string, $length));
219219
}
220220

221+
/**
222+
* @covers \Symfony\Polyfill\Intl\Grapheme\Grapheme::grapheme_str_split
223+
*/
224+
public function testGraphemeStrSplitNegativeLength()
225+
{
226+
$this->expectException(\ValueError::class);
227+
228+
grapheme_str_split('abc', -1);
229+
}
230+
221231
public static function graphemeStrSplitDataProvider(): array
222232
{
223233
$cases = [
@@ -288,12 +298,11 @@ public function testGraphemeLevenshteinInvalidUtf8()
288298

289299
/**
290300
* @covers \Symfony\Polyfill\Intl\Grapheme\Grapheme::grapheme_levenshtein
291-
*
292-
* @requires PHP 8
293301
*/
294302
public function testGraphemeLevenshteinNegativeCost()
295303
{
296304
$this->expectException(\ValueError::class);
305+
297306
grapheme_levenshtein('a', 'b', -1);
298307
}
299308

tests/Php85/Php85Test.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,26 @@ public function testLocaleIsRightToLeft()
154154
$this->assertFalse(locale_is_right_to_left('zh'));
155155
$this->assertFalse(locale_is_right_to_left(''));
156156
}
157+
158+
/**
159+
* @requires extension intl
160+
*/
161+
public function testGraphemeLevenshtein()
162+
{
163+
$this->assertSame(3, grapheme_levenshtein('kitten', 'sitting'));
164+
$this->assertSame(1, grapheme_levenshtein('한국어', '한국'));
165+
$this->assertFalse(grapheme_levenshtein("\xFF", 'a'));
166+
}
167+
168+
/**
169+
* @requires extension intl
170+
*/
171+
public function testGraphemeLevenshteinNegativeCost()
172+
{
173+
$this->expectException(\ValueError::class);
174+
175+
grapheme_levenshtein('a', 'b', -1);
176+
}
157177
}
158178

159179
class TestHandler

0 commit comments

Comments
 (0)