Skip to content

Stdlib: grapheme_* — Unicode grapheme cluster string API (ext/intl/grapheme parity) #3352

Description

@PurHur

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:vmVirtual machineenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-4:stdlibPhase 4 – stdlib for web apps

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions