Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions docs/bootstrap-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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`

Expand Down
16 changes: 1 addition & 15 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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) |
Expand Down
20 changes: 3 additions & 17 deletions docs/pages/capability-comparison.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ <h1>PHP capability comparison</h1>
</article>
<article>
<div>Stdlib builtins</div>
<strong>1171</strong> / 1566 full (VM+JIT+AOT)
<p style="margin:0.35rem 0 0;font-size:0.88rem;color:var(--text-muted)">362 partial · 33 gaps</p>
<strong>1170</strong> / 1552 full (VM+JIT+AOT)
<p style="margin:0.35rem 0 0;font-size:0.88rem;color:var(--text-muted)">348 partial · 34 gaps</p>
</article>
<article>
<div>Legend</div>
Expand Down Expand Up @@ -680,21 +680,8 @@ <h2>Stdlib builtins</h2>
<tr data-support="full"><td><code>`gmp_testbit`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`gmp_xor`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`gmstrftime`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_adddecryptkey`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_addencryptkey`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_addsignkey`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_cleardecryptkeys`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_clearencryptkeys`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_clearsignkeys`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_decrypt`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_encrypt`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_geterror`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_init`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_keyinfo`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_sign`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`gnupg_verify`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="full"><td><code>`grapheme_extract`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`grapheme_levenshtein`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="gap"><td><code>`grapheme_levenshtein`</code></td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="full"><td><code>`grapheme_stripos`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`grapheme_stristr`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
<tr data-support="full"><td><code>`grapheme_strlen`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-yes">yes</td><td>—</td></tr>
Expand Down Expand Up @@ -846,7 +833,6 @@ <h2>Stdlib builtins</h2>
<tr data-support="partial"><td><code>`intltz_get_error_code`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_error_message`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_gmt`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_iana_id`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_id`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_id_for_windows_id`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
<tr data-support="partial"><td><code>`intltz_get_offset`</code></td><td class="status-yes">yes</td><td class="status-yes">yes</td><td class="status-no">no</td><td class="status-no">no</td><td>—</td></tr>
Expand Down
3 changes: 2 additions & 1 deletion ext/intl/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
5 changes: 3 additions & 2 deletions ext/intl/grapheme_levenshtein.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
19 changes: 19 additions & 0 deletions lib/CompilerVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -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).
*
Expand Down
7 changes: 7 additions & 0 deletions script/capability-syntax-lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
10 changes: 10 additions & 0 deletions test/compliance/JITTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
10 changes: 10 additions & 0 deletions test/compliance/VMTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()).
Expand Down
Original file line number Diff line number Diff line change
@@ -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--
<?php
echo function_exists('grapheme_levenshtein') ? "fail\n" : "ok\n";
echo is_callable('grapheme_levenshtein') ? "fail\n" : "ok\n";
--EXPECT--
ok
ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--TEST--
stdlib grapheme_levenshtein() — not advertised on any profile (Zend never ships; #22661 / #6998)
--FILE--
<?php
echo function_exists('grapheme_levenshtein') ? "fail\n" : "ok\n";
echo is_callable('grapheme_levenshtein') ? "fail\n" : "ok\n";
--EXPECT--
ok
ok
11 changes: 4 additions & 7 deletions test/repro-maintainer/grapheme_levenshtein_missing.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
<?php
declare(strict_types=1);

if (!function_exists('grapheme_levenshtein')) {
fwrite(STDERR, "MISSING grapheme_levenshtein\n");
// Issue #22661 — Zend/php-src never ships grapheme_levenshtein(); must stay missing.
if (function_exists('grapheme_levenshtein')) {
fwrite(STDERR, "PHANTOM grapheme_levenshtein still registered\n");
exit(1);
}

// NFC vs NFD of "café" — grapheme distance should be 0; byte levenshtein may differ
$nfc = "caf\u{00E9}";
$nfd = "caf\u{0065}\u{0301}";
echo grapheme_levenshtein($nfc, $nfd), "\n";
echo grapheme_levenshtein('kitten', 'sitting'), "\n";
echo "ok\n";
6 changes: 6 additions & 0 deletions test/repro/maintainer_gap_grapheme_levenshtein_phantom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

declare(strict_types=1);

// Issue #22661 — grapheme_levenshtein() must not be advertised (Zend/php-src never ships it).
echo function_exists('grapheme_levenshtein') ? "fail\n" : "ok\n";
32 changes: 32 additions & 0 deletions test/unit/CompilerVersionBuiltinAdvertisementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,38 @@ public function testMbUcwordsWithheldOnForwardProfile(): void
}
}

public function testGraphemeLevenshteinWithheldOnReferenceProfile(): void
{
$prev = getenv('PHP_COMPILER_PROFILE');
putenv('PHP_COMPILER_PROFILE');
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 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();
Expand Down
Loading