Multibyte strings7 min readExamples run on PHP 8.5.10

mb_str_split()

Learn how mb_str_split() splits multibyte strings into characters or fixed-size chunks in PHP 8.4, with examples, edge cases and common mistakes.

Signature

mb_str_split(string $string, int $length = 1, ?string $encoding = null): array
Available since PHP 7.4.07.48.08.18.28.38.48.5All versions →

Purpose

mb_str_split() breaks a string into an array of pieces, counting in characters instead of bytes. It is the multibyte-aware counterpart of str_split(). That matters for UTF-8 text, where a single character such as é or 日 takes two or more bytes. str_split() would cut those characters apart and produce invalid fragments. mb_str_split() keeps each character whole.

Signature

Parameters and defaults

  • $string: the text to split.
  • $length: the number of characters in each element. The default is 1, so you get one character per element. With a larger value, the string is cut into chunks of that many characters. The last chunk may be shorter.
  • $encoding: the character encoding, such as "UTF-8". If you omit it or pass null, PHP uses the internal encoding. The manual calls it good practice to pass the encoding explicitly, so the result does not depend on configuration.

Return value and failure cases

The function returns an array of strings. Since PHP 8.0 it no longer returns false on failure, so you do not need a false check. An invalid $encoding name throws a ValueError. Before PHP 8.0 it emitted a warning instead. A $length below 1 is also rejected with a ValueError.

Example 1: one character per element

With the default length, each character becomes its own element, even if it uses several bytes.

Example
<?php
$text = "héllo";
$chars = mb_str_split($text, 1, "UTF-8");
echo json_encode($chars, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["h","é","l","l","o"]

The accented letter stays intact, so the array has five elements.

Example 2: chunks and the byte comparison

The second argument sets the chunk size in characters. The example also shows why byte-based splitting is the wrong tool for this text.

Example
<?php
$text = "日本語テキスト";
echo json_encode(mb_str_split($text, 3, "UTF-8"), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode([
    "bytes" => count(str_split("日本語")),
    "characters" => count(mb_str_split("日本語", 1, "UTF-8")),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["日本語","テキス","ト"]
{"bytes":9,"characters":3}

The seven characters become chunks of 3, 3 and 1. The three-character word 日本語 is nine bytes in UTF-8, so str_split() returns nine fragments while mb_str_split() returns three characters.

Example 3: empty input and errors

An empty string produces an empty array. Invalid arguments raise ValueError, which you can catch.

Example
<?php
echo json_encode(mb_str_split("", 1, "UTF-8")), "\n";
foreach ([["abc", 0, "UTF-8"], ["abc", 1, "NOPE"]] as [$s, $l, $e]) {
    try {
        mb_str_split($s, $l, $e);
    } catch (ValueError $error) {
        echo get_class($error), "\n";
    }
}
Output
[]
ValueError
ValueError

Both bad calls are rejected: the first because of the length, the second because of the unknown encoding name.

Edge cases

  • Empty string: you get [], not an array holding an empty string. Do not assume $parts[0] exists.
  • Last chunk: when the character count is not a multiple of $length, the final element is shorter.
  • Characters are not always what users see. In UTF-8 the function works on code points. A letter followed by a combining accent, or an emoji built from several code points, is split into several elements. If you need user-perceived characters, look at grapheme_str_split(), which the manual lists as a related function.
  • Encoding mismatch: if the bytes are not valid in the chosen encoding, the split is not meaningful. Make sure the data really is in the encoding you pass.
  • Memory: splitting a very long string with length 1 creates one array element per character, which can use far more memory than the original string.

Common mistakes

  1. Using str_split() on UTF-8 text. It splits by bytes and can produce broken characters. Use mb_str_split() whenever non-ASCII input is possible.
  2. Treating $length as a byte count. It counts characters.
  3. Relying on the default encoding. Pass "UTF-8" explicitly so behaviour does not depend on the internal encoding setting.
  4. Checking for false. Modern PHP does not return it. Catch ValueError only if the encoding or length comes from untrusted input.
  5. Expecting grapheme clusters. Code points are not always the same as visible symbols.
  6. Splitting by a delimiter. If you need to split on a separator, use explode(). mb_str_split() only cuts by size.
  • str_split(): the byte-based version, fine for pure ASCII or binary data.
  • grapheme_str_split(): splits by grapheme clusters.
  • explode(): splits by a separator string.

Recap

mb_str_split($string, $length = 1, $encoding = null) returns an array of strings, each holding up to $length characters. Pass the encoding explicitly, expect [] for empty input, and remember that invalid arguments throw ValueError. It splits by code points, which makes it a safe replacement for str_split() with UTF-8 text.

Tested examples

Split a string into single characters
<?php
$text = "héllo";
$chars = mb_str_split($text, 1, "UTF-8");
echo json_encode($chars, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["h","é","l","l","o"]
Chunk by characters and compare with byte splitting
<?php
$text = "日本語テキスト";
echo json_encode(mb_str_split($text, 3, "UTF-8"), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode([
    "bytes" => count(str_split("日本語")),
    "characters" => count(mb_str_split("日本語", 1, "UTF-8")),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["日本語","テキス","ト"]
{"bytes":9,"characters":3}
Empty string and ValueError cases
<?php
echo json_encode(mb_str_split("", 1, "UTF-8")), "\n";
foreach ([["abc", 0, "UTF-8"], ["abc", 1, "NOPE"]] as [$s, $l, $e]) {
    try {
        mb_str_split($s, $l, $e);
    } catch (ValueError $error) {
        echo get_class($error), "\n";
    }
}
Output
[]
ValueError
ValueError