A PHP string is a sequence of bytes, and characters like é or an emoji take more than one byte, so looping over a string byte by byte can split them apart. This RFC from Masaki Kagaya adds str_iter(), which lets you loop over a string one UTF-8 code point at a time. A code point is a single Unicode character, however many bytes it takes.
Show me
foreach (str_iter("héllo🙂") as $index => $char) { var_dump($index, $char); }
The RFC shows this output:
int(0) string(1) "h" int(1) string(2) "é" int(2) string(1) "l" int(3) string(1) "l" int(4) string(1) "o" int(5) string(4) "🙂"
Each iteration gives you one character as a string. The keys count characters from zero rather than byte offsets, so 🙂 sits at key 5 even though it takes 4 bytes.
How it works
The signature is:
str_iter(string $str): Traversable
It returns an object you can iterate more than once, without building an array first.
It doesn't validate the string as UTF-8, so it won't report errors or swap in replacement characters. When it hits broken bytes, it still advances at least one byte each step, which guarantees the loop ends.
It works on code points, not grapheme clusters. A grapheme cluster is what a reader sees as one character, and it can be made of several code points. Grapheme support, UTF-8 validation, and length or substring functions are all left for later RFCs.
Why add it
The RFC points to code that already solves this in other ways. WordPress 6.9 added its own UTF-8 parser, and Symfony Polyfill reimplements mbstring in plain PHP. mbstring has mb_str_split(), intl has IntlCodePointBreakIterator, and PHP's own C code already walks UTF-8 in ext/standard/html.c.
The author wants this in core rather than in mbstring, so it's available everywhere without an extension.
What it means for existing code
Nothing breaks, since it's a new function.
Where it stands
The RFC is a draft dated March 24, 2026. It has no implementation link and no vote yet.