From 8f5261bc5c71e29e87edcdc2ff6958d245911bdc Mon Sep 17 00:00:00 2001 From: PurHur Date: Thu, 23 Jul 2026 15:02:35 +0000 Subject: [PATCH] =?UTF-8?q?Stdlib:=20withhold=20grapheme=5Flevenshtein()?= =?UTF-8?q?=20=E2=80=94=20Zend=20never=20ships=20it=20(#22661)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match php-src grapheme.stub.php / mb_ucwords phantom gate: always-false supports/advertises so function_exists stays false on every profile. Co-authored-by: Cursor --- docs/bootstrap-inventory.md | 16 +++++----- docs/capabilities.md | 16 +--------- docs/pages/capability-comparison.html | 20 ++---------- ext/intl/Module.php | 3 +- ext/intl/grapheme_levenshtein.php | 5 +-- lib/CompilerVersion.php | 19 +++++++++++ script/capability-syntax-lib.php | 7 ++++ test/compliance/JITTest.php | 10 ++++++ test/compliance/VMTest.php | 10 ++++++ .../grapheme_levenshtein_forward_profile.phpt | 11 +++++++ .../stdlib/grapheme_levenshtein_phantom.phpt | 9 ++++++ .../grapheme_levenshtein_missing.php | 11 +++---- ...ainer_gap_grapheme_levenshtein_phantom.php | 6 ++++ ...ompilerVersionBuiltinAdvertisementTest.php | 32 +++++++++++++++++++ 14 files changed, 125 insertions(+), 50 deletions(-) create mode 100644 test/compliance/cases/stdlib/grapheme_levenshtein_forward_profile.phpt create mode 100644 test/compliance/cases/stdlib/grapheme_levenshtein_phantom.phpt create mode 100644 test/repro/maintainer_gap_grapheme_levenshtein_phantom.php diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index 981149d4b3d..f8aa44ac896 100644 --- a/docs/bootstrap-inventory.md +++ b/docs/bootstrap-inventory.md @@ -13161,13 +13161,13 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new grapheme_strrpos (line 354) - new grapheme_strripos (line 355) - new grapheme_extract (line 356) -- new grapheme_levenshtein (line 357) -- new grapheme_str_split (line 358) -- new grapheme_strimwidth (line 359) -- new intl_get_error_code (line 360) -- new intl_get_error_message (line 361) -- new intl_is_failure (line 362) -- new intl_error_name (line 363) +- new grapheme_levenshtein (line 358) +- new grapheme_str_split (line 359) +- new grapheme_strimwidth (line 360) +- new intl_get_error_code (line 361) +- new intl_get_error_message (line 362) +- new intl_is_failure (line 363) +- new intl_error_name (line 364) - 4 class method(s) ### `ext/intl/NormalizerGetRawDecomposition.php` @@ -41044,7 +41044,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `lib/CompilerVersion.php` **Warnings** (review for bootstrap subset): -- 243 class method(s) +- 245 class method(s) ### `lib/CurlyBraceOffsetRejector.php` diff --git a/docs/capabilities.md b/docs/capabilities.md index c53bffb529c..f374d465516 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -501,21 +501,8 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `gmp_testbit` | yes | yes | yes | gmp | | | `gmp_xor` | yes | yes | yes | gmp | | | `gmstrftime` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | -| `gnupg_adddecryptkey` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_addencryptkey` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_addsignkey` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_cleardecryptkeys` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_clearencryptkeys` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_clearsignkeys` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_decrypt` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_encrypt` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_geterror` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_init` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_keyinfo` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_sign` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | -| `gnupg_verify` | yes | no | no | gnupg | not implemented for JIT in this compiler build (issue #6668) | | `grapheme_extract` | yes | yes | yes | intl | JIT PHPT | -| `grapheme_levenshtein` | yes | yes | yes | intl | JIT PHPT | +| `grapheme_levenshtein` | no | no | no | intl | impl present; gated (8.4.0 ref, since 8.4.0); JIT PHPT | | `grapheme_stripos` | yes | yes | yes | intl | JIT PHPT; AOT PHPT | | `grapheme_stristr` | yes | yes | yes | intl | | | `grapheme_strlen` | yes | yes | yes | intl | JIT PHPT | @@ -667,7 +654,6 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `intltz_get_error_code` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20925) | | `intltz_get_error_message` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20925) | | `intltz_get_gmt` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20859) | -| `intltz_get_iana_id` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20925) | | `intltz_get_id` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20859) | | `intltz_get_id_for_windows_id` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20925) | | `intltz_get_offset` | yes | no | no | intl | not implemented for JIT in this compiler build (issue #20925) | diff --git a/docs/pages/capability-comparison.html b/docs/pages/capability-comparison.html index 6beac802ef4..92ae4f403d9 100644 --- a/docs/pages/capability-comparison.html +++ b/docs/pages/capability-comparison.html @@ -64,8 +64,8 @@

PHP capability comparison

Stdlib builtins
- 1171 / 1566 full (VM+JIT+AOT) -

362 partial · 33 gaps

+ 1170 / 1552 full (VM+JIT+AOT) +

348 partial · 34 gaps

Legend
@@ -680,21 +680,8 @@

Stdlib builtins

`gmp_testbit`yesyesyesyes— `gmp_xor`yesyesyesyes— `gmstrftime`yesyesyesyes— -`gnupg_adddecryptkey`yesyesnono— -`gnupg_addencryptkey`yesyesnono— -`gnupg_addsignkey`yesyesnono— -`gnupg_cleardecryptkeys`yesyesnono— -`gnupg_clearencryptkeys`yesyesnono— -`gnupg_clearsignkeys`yesyesnono— -`gnupg_decrypt`yesyesnono— -`gnupg_encrypt`yesyesnono— -`gnupg_geterror`yesyesnono— -`gnupg_init`yesyesnono— -`gnupg_keyinfo`yesyesnono— -`gnupg_sign`yesyesnono— -`gnupg_verify`yesyesnono— `grapheme_extract`yesyesyesyes— -`grapheme_levenshtein`yesyesyesyes— +`grapheme_levenshtein`yesnonono— `grapheme_stripos`yesyesyesyes— `grapheme_stristr`yesyesyesyes— `grapheme_strlen`yesyesyesyes— @@ -846,7 +833,6 @@

Stdlib builtins

`intltz_get_error_code`yesyesnono— `intltz_get_error_message`yesyesnono— `intltz_get_gmt`yesyesnono— -`intltz_get_iana_id`yesyesnono— `intltz_get_id`yesyesnono— `intltz_get_id_for_windows_id`yesyesnono— `intltz_get_offset`yesyesnono— diff --git a/ext/intl/Module.php b/ext/intl/Module.php index add1c6c723e..022e097d5c8 100644 --- a/ext/intl/Module.php +++ b/ext/intl/Module.php @@ -354,7 +354,8 @@ public function getFunctions(): array new grapheme_strrpos(), new grapheme_strripos(), new grapheme_extract(), - new grapheme_levenshtein(), + // Never shipped by Zend — withhold on every profile (#22661 / #6998). + ...(CompilerVersion::supportsGraphemeLevenshtein() ? [new grapheme_levenshtein()] : []), ...(CompilerVersion::supportsGraphemeStrSplit() ? [new grapheme_str_split()] : []), ...(CompilerVersion::supportsGraphemeStrimwidth() ? [new grapheme_strimwidth()] : []), new intl_get_error_code(), diff --git a/ext/intl/grapheme_levenshtein.php b/ext/intl/grapheme_levenshtein.php index 4ebb278788e..e53b40d3486 100644 --- a/ext/intl/grapheme_levenshtein.php +++ b/ext/intl/grapheme_levenshtein.php @@ -15,9 +15,10 @@ use PHPLLVM\Value; /** - * grapheme_levenshtein() — grapheme-cluster edit distance (php-src ext/intl/grapheme; #6998). + * grapheme_levenshtein() — grapheme-cluster edit distance (not shipped by Zend; kept unregistered, #22661). * - * VM: {@see VmGrapheme}; JIT: compile-time fold via {@see JitGrapheme} (runtime defer #6998). + * Historical experiment (#6998). Zend/php-src has no stub entry (php/php-src#10180). + * Internal helper remains at {@see VmGrapheme::levenshtein()} for unit tests. */ final class grapheme_levenshtein extends Internal { diff --git a/lib/CompilerVersion.php b/lib/CompilerVersion.php index f54588dea1b..112b7272fe1 100644 --- a/lib/CompilerVersion.php +++ b/lib/CompilerVersion.php @@ -1917,6 +1917,25 @@ public static function advertisesGraphemeStrContains(): bool return false; } + /** + * grapheme_levenshtein() — never shipped by Zend/php-src (ext/intl/grapheme/grapheme.stub.php). + * + * Prior registration (#6998) was wrong-direction: ICU levenshtein RFC never landed in stubs + * (php/php-src#10180). Always withheld — #22661. + */ + public static function supportsGraphemeLevenshtein(): bool + { + return false; + } + + /** + * grapheme_levenshtein() visible to function_exists() — always false (Zend never ships it; #22661). + */ + public static function advertisesGraphemeLevenshtein(): bool + { + return false; + } + /** * PHP 8.4+ grapheme_strimwidth() (ext/intl/grapheme/grapheme_string.c, issue #9793, #17010). * diff --git a/script/capability-syntax-lib.php b/script/capability-syntax-lib.php index bbf1addcd67..76de116ad35 100644 --- a/script/capability-syntax-lib.php +++ b/script/capability-syntax-lib.php @@ -1394,6 +1394,13 @@ function withheldBuiltinGateDefinitions(): array 'module' => 'mbstring', 'relPath' => 'ext/mbstring/mb_ucwords.php', ], + [ + 'names' => ['grapheme_levenshtein'], + 'gate' => [PHPCompiler\CompilerVersion::class, 'supportsGraphemeLevenshtein'], + 'since' => '8.4.0', + 'module' => 'intl', + 'relPath' => 'ext/intl/grapheme_levenshtein.php', + ], [ 'names' => ['generator_to_array'], 'gate' => [PHPCompiler\CompilerVersion::class, 'supportsGeneratorToArray'], diff --git a/test/compliance/JITTest.php b/test/compliance/JITTest.php index cc65dd46a1e..d3fce199302 100755 --- a/test/compliance/JITTest.php +++ b/test/compliance/JITTest.php @@ -431,6 +431,16 @@ public static function providePHPTests(): \Generator && str_contains($name, 'mb_ucwords_phantom')) { continue; } + if (!CompilerVersion::supportsGraphemeLevenshtein() + && str_contains($name, 'grapheme_levenshtein') + && !str_contains($name, 'grapheme_levenshtein_phantom') + && !str_contains($name, 'grapheme_levenshtein_forward')) { + continue; + } + if (CompilerVersion::supportsGraphemeLevenshtein() + && str_contains($name, 'grapheme_levenshtein_phantom')) { + continue; + } if (!CompilerVersion::supportsStreamSupports() && (('stdlib/stream_supports' === $name) || str_contains($name, 'stream_support_constants') diff --git a/test/compliance/VMTest.php b/test/compliance/VMTest.php index 337e0f73c20..8712ea4182f 100755 --- a/test/compliance/VMTest.php +++ b/test/compliance/VMTest.php @@ -508,6 +508,16 @@ public static function providePHPTests(): \Generator && str_contains($name, 'mb_ucwords_phantom')) { continue; } + if (!CompilerVersion::supportsGraphemeLevenshtein() + && str_contains($name, 'grapheme_levenshtein') + && !str_contains($name, 'grapheme_levenshtein_phantom') + && !str_contains($name, 'grapheme_levenshtein_forward')) { + continue; + } + if (CompilerVersion::supportsGraphemeLevenshtein() + && str_contains($name, 'grapheme_levenshtein_phantom')) { + continue; + } // convert_cyr_string / money_format removed in php-src 8.0 (#21481): functional cases use // PROFILE=7.4 via --ENV--; phantom_* cases assert absence on 8.2/8.4 — always include // (do not gate on supportsConvertCyrString()/supportsMoneyFormat()). diff --git a/test/compliance/cases/stdlib/grapheme_levenshtein_forward_profile.phpt b/test/compliance/cases/stdlib/grapheme_levenshtein_forward_profile.phpt new file mode 100644 index 00000000000..90e53697c67 --- /dev/null +++ b/test/compliance/cases/stdlib/grapheme_levenshtein_forward_profile.phpt @@ -0,0 +1,11 @@ +--TEST-- +stdlib grapheme_levenshtein() — phantom on PHP_COMPILER_PROFILE=8.4 (Zend never ships; #22661) +--ENV-- +PHP_COMPILER_PROFILE=8.4 +--FILE-- +assertFalse(CompilerVersion::supportsGraphemeLevenshtein()); + $this->assertFalse(CompilerVersion::advertisesGraphemeLevenshtein()); + } finally { + if (false === $prev) { + putenv('PHP_COMPILER_PROFILE'); + } else { + putenv('PHP_COMPILER_PROFILE='.$prev); + } + } + } + + public function testGraphemeLevenshteinWithheldOnForwardProfile(): void + { + $prev = getenv('PHP_COMPILER_PROFILE'); + putenv('PHP_COMPILER_PROFILE=8.4'); + try { + $this->assertFalse(CompilerVersion::supportsGraphemeLevenshtein()); + $this->assertFalse(CompilerVersion::advertisesGraphemeLevenshtein()); + } finally { + if (false === $prev) { + putenv('PHP_COMPILER_PROFILE'); + } else { + putenv('PHP_COMPILER_PROFILE='.$prev); + } + } + } + public function testVmDoesNotRegisterMbStrPadOnDefault84DevReference(): void { $runtime = new Runtime();