Multibyte strings7 min readExamples run on PHP 8.5.10

mb_trim()

Learn how PHP 8.4 mb_trim() removes Unicode whitespace or custom characters from both ends of a string, with examples, edge cases and mistakes.

Signature

mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string
Available since PHP 8.4.07.48.08.18.28.38.48.5All versions →

Purpose

mb_trim() removes characters from the beginning and end of a string, like trim(), but it works on whole characters in a given encoding instead of single bytes. This matters for text from forms, imports and copy-pasted documents, where the padding is often a no-break space or an ideographic space rather than an ASCII space. The function is available from PHP 8.4.0.

Signature

Parameters and defaults

  • $string: the text to trim.
  • $characters: optional. When it is null, a built-in set of whitespace characters is removed. That set includes the ASCII space, tab, line feed, carriage return, NUL and vertical tab. It also includes form feed, U+00A0 no-break space, U+1680, the U+2000 to U+200A spaces, U+2028, U+2029, U+202F, U+205F, U+3000 ideographic space, U+0085 and U+180E. When you pass a string, you list every character to strip.
  • $encoding: optional. When it is null, PHP uses the internal character encoding.

Return value and failure cases

The function returns the trimmed string. If everything is stripped, the result is an empty string. Only the two ends are touched, so characters in the middle are never removed. An unknown encoding name raises a ValueError, as it does in other multibyte functions.

Example 1: Unicode whitespace versus trim()

The sample text is padded with an ideographic space, a no-break space, a normal space and an em space. Plain trim() only knows ASCII-style whitespace bytes. Here it removes only the final newline, so the Unicode padding stays.

Example
<?php
$text = "\u{3000}\u{00A0} Café \u{2003}\n";
$clean = mb_trim($text, null, 'UTF-8');
echo json_encode([
    'mb_trim' => $clean,
    'mb_trim_length' => mb_strlen($clean),
    'trim_length' => mb_strlen(trim($text)),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"mb_trim":"Café","mb_trim_length":4,"trim_length":9}

Example 2: Custom character lists

When you supply $characters, that list is used in place of the default whitespace set. To strip decoration and spaces together, include both in the list.

Example
<?php
$label = "★★ Hello ★★";
echo json_encode([
    'stars_only' => mb_trim($label, "★"),
    'stars_and_space' => mb_trim($label, "★ "),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"stars_only":" Hello ","stars_and_space":"Hello"}

The first call stops at the spaces because they are not in its list. The second call removes the stars and the spaces.

Example 3: Empty results, inner characters and bad encodings

Example
<?php
echo json_encode([
    'empty' => mb_trim("\u{2003}\u{2003}"),
    'inner' => mb_trim("  a\u{3000}b  "),
], JSON_UNESCAPED_SLASHES), "\n";

try {
    mb_trim('x', null, 'not-an-encoding');
} catch (ValueError $e) {
    echo "ValueError\n";
}
Output
{"empty":"","inner":"a\u3000b"}
ValueError

The JSON here is deliberately left in escaped form, so the ideographic space between a and b appears as \u3000. That shows it survived trimming.

Edge cases

  • A string made only of trimmable characters becomes "".
  • Whitespace inside the text is preserved. Use another tool, such as a regular expression, if you also need to collapse internal runs.
  • A custom list replaces the defaults, so a string with both stars and spaces needs both characters in the list.
  • Passing an explicit encoding is useful in libraries, because it does not depend on the application's internal encoding setting.
  • The function trims characters, not visual glyphs. A user-perceived character made of several code points is not treated as one unit just because it looks like one.

Common mistakes

  1. Using trim() for Unicode text. It works on bytes and ignores non-ASCII whitespace such as U+00A0 or U+3000. It can also be unsafe with a custom list of multibyte characters, because each byte is treated as a separate character.
  2. Assuming a custom list adds to the defaults. If you pass "-", spaces are no longer stripped.
  3. Expecting it to normalize text. It does not collapse inner spaces, change case or apply Unicode normalization.
  4. Mismatching the encoding. Declaring one encoding while the data is in another gives unreliable results. Make sure your input is valid in the encoding you name.
  5. Forgetting that older PHP versions lack it. The function belongs to PHP 8.4 and later. Code that must run on earlier versions needs another approach.
  • mb_ltrim() strips only from the beginning.
  • mb_rtrim() strips only from the end.
  • trim() is the byte-based version, which is fine for ASCII-only data.
  • mb_strlen() and mb_substr() are often used with it when validating or measuring text.

Recap

Use mb_trim() when text may contain Unicode whitespace or when your custom trim list contains multibyte characters. With no second argument it removes a broad set of whitespace characters. With a second argument it removes exactly the characters you list. It leaves the interior untouched, returns a string, and throws ValueError for an unknown encoding name.

Tested examples

Unicode whitespace versus trim()
<?php
$text = "\u{3000}\u{00A0} Café \u{2003}\n";
$clean = mb_trim($text, null, 'UTF-8');
echo json_encode([
    'mb_trim' => $clean,
    'mb_trim_length' => mb_strlen($clean),
    'trim_length' => mb_strlen(trim($text)),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"mb_trim":"Café","mb_trim_length":4,"trim_length":9}
Custom character lists
<?php
$label = "★★ Hello ★★";
echo json_encode([
    'stars_only' => mb_trim($label, "★"),
    'stars_and_space' => mb_trim($label, "★ "),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"stars_only":" Hello ","stars_and_space":"Hello"}
Empty results, inner characters and bad encodings
<?php
echo json_encode([
    'empty' => mb_trim("\u{2003}\u{2003}"),
    'inner' => mb_trim("  a\u{3000}b  "),
], JSON_UNESCAPED_SLASHES), "\n";

try {
    mb_trim('x', null, 'not-an-encoding');
} catch (ValueError $e) {
    echo "ValueError\n";
}
Output
{"empty":"","inner":"a\u3000b"}
ValueError