Category
stdlib
Status (refreshed 2026-06-18 — implementation-ready worker spec)
Partial landing (VM): ext/intl/VmGrapheme.php + ext/intl/grapheme_*.php register several helpers. Verified on bin/vm.php:
| Function |
function_exists (VM) |
Notes |
grapheme_strlen |
✅ true |
VM delegate |
grapheme_substr |
✅ true |
VM delegate |
grapheme_strpos / strstr / stripos / … |
✅ true |
see ext/intl/grapheme_*.php |
grapheme_str_split |
✅ true |
#6246 — landed; JIT + compliance still open |
grapheme_levenshtein |
❌ false |
#3352 slice |
Remaining gaps: JIT/AOT lowering (most throw deferred), self-host without host ICU, enum-case operand TypeError guards (#5914), compliance PHPT coverage.
Problem
grapheme_* helpers from ext/intl provide user-visible string length/search/split on grapheme clusters (combining marks stay attached). Frameworks and Symfony String use them beyond byte/UTF-8 code units.
php-src reference
Repro — strlen/substr (VM should match Zend when host intl available)
Save as test/repro-maintainer/grapheme_strlen_substr.php:
<?php
declare(strict_types=1);
$s = "a\xCC\x81b"; // a + combining acute + b => 2 graphemes
echo grapheme_strlen($s), "\n";
echo bin2hex(grapheme_substr($s, 0, 1)), "\n";
echo grapheme_strpos($s, 'b'), "\n";
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php test/repro-maintainer/grapheme_strlen_substr.php
php bin/vm.php test/repro-maintainer/grapheme_strlen_substr.php'
| Engine |
grapheme_strlen |
first cluster hex |
strpos b |
| Zend + ext/intl |
2 |
61cc81 |
2 |
| VM (target) |
same |
same |
same |
Repro — missing grapheme_levenshtein
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php bin/vm.php test/repro-maintainer/grapheme_levenshtein_missing.php 2>&1 | head -3'
# MISSING grapheme_levenshtein
Scope (PHP-in-PHP)
| Area |
Path |
Notes |
| VM |
ext/intl/VmGrapheme.php, ext/intl/grapheme_*.php |
ICU via host intl acceptable phase 1; document bootstrap path |
| JIT |
ext/intl/JitGrapheme.php (new) |
Remove "deferred" throws; pair with #5914 enum guards |
| Module |
ext/intl/Module.php |
Register all grapheme builtins |
| Tests |
test/compliance/cases/stdlib/grapheme_*.phpt |
strlen, substr, strpos, str_split, levenshtein |
| Matrix |
php script/capability-matrix.php |
JIT column updates |
Not in scope here: full ext/intl ICU formatting (#3336, #5153 Normalizer).
Done when
Child / related issues
Category
stdlibStatus (refreshed 2026-06-18 — implementation-ready worker spec)
Partial landing (VM):
ext/intl/VmGrapheme.php+ext/intl/grapheme_*.phpregister several helpers. Verified onbin/vm.php:function_exists(VM)grapheme_strlengrapheme_substrgrapheme_strpos/strstr/stripos/ …ext/intl/grapheme_*.phpgrapheme_str_splitgrapheme_levenshteinRemaining gaps: JIT/AOT lowering (most throw deferred), self-host without host ICU, enum-case operand
TypeErrorguards (#5914), compliance PHPT coverage.Problem
grapheme_*helpers from ext/intl provide user-visible string length/search/split on grapheme clusters (combining marks stay attached). Frameworks and Symfony String use them beyond byte/UTF-8 code units.php-src reference
ext/intl/grapheme/grapheme_string.c—grapheme_strlen,grapheme_substr,grapheme_strpos, …ext/intl/grapheme/grapheme_util.c— ICU grapheme break iteratorRepro — strlen/substr (VM should match Zend when host intl available)
Save as
test/repro-maintainer/grapheme_strlen_substr.php:grapheme_strlenstrpos b261cc812Repro — missing
grapheme_levenshteinScope (PHP-in-PHP)
ext/intl/VmGrapheme.php,ext/intl/grapheme_*.phpintlacceptable phase 1; document bootstrap pathext/intl/JitGrapheme.php(new)ext/intl/Module.phptest/compliance/cases/stdlib/grapheme_*.phptphp script/capability-matrix.phpNot in scope here: full ext/intl ICU formatting (#3336, #5153 Normalizer).
Done when
test/repro-maintainer/grapheme_strlen_substr.phpmatches Zend on VMgrapheme_levenshteinregistered with Zend parity on NFC/NFD sample (Stdlib: grapheme_* — Unicode grapheme cluster string API (ext/intl/grapheme parity) #3352 levenshtein slice)TypeErrorper Stdlib: grapheme_*() — enum case string operands must TypeError (ext/intl/grapheme) #5914 (shared compliance phpt)./script/ci-fast.sh --filter graphemegreenChild / related issues
grapheme_str_split(VM landed — close when JIT+PHPT green)