Multibyte strings7 min readExamples run on PHP 8.5.10

mb_convert_case()

Learn how mb_convert_case() converts multibyte strings to upper, lower, title or folded case in PHP 8.4, with examples, edge cases and common mistakes.

Signature

mb_convert_case(string $string, int $mode, ?string $encoding = null): string
Available since PHP 4.3.07.48.08.18.28.38.48.5All versions →

Purpose

mb_convert_case() changes the case of a string using Unicode character properties. Unlike strtolower() and strtoupper(), it understands multibyte text, so letters such as é, ä or Greek characters are converted properly. One function covers several conversions, selected by a mode constant: upper, lower, title and case folding, each with a full and a "simple" variant.

The manual notes that this function works from Unicode properties, so locale settings do not affect it. That makes results more predictable than the single-byte functions.

Signature

Parameters and defaults

  • $string: the text to convert.
  • $mode: one of MB_CASE_UPPER, MB_CASE_LOWER, MB_CASE_TITLE, MB_CASE_FOLD, MB_CASE_UPPER_SIMPLE, MB_CASE_LOWER_SIMPLE, MB_CASE_TITLE_SIMPLE or MB_CASE_FOLD_SIMPLE. There is no default; you must pass a mode.
  • $encoding: the character encoding of the input. It defaults to null, which means the internal encoding configured for the mbstring extension is used. Passing "UTF-8" explicitly makes your code independent of that setting.

Return value and failure cases

The function returns the converted string. If $encoding is not a valid encoding name, PHP 8 throws a ValueError. Before PHP 8.0.0 this produced a warning instead, so older code that checked for a false return no longer applies on PHP 8.4.

The manual's changelog adds that the simple and folding modes were added in PHP 7.3.0, and that in PHP 8.3.0 the conditional casing rules for the Greek letter sigma were implemented. They apply only to MB_CASE_LOWER and MB_CASE_TITLE, not to the _SIMPLE variants.

Example 1: upper and title case

Title mode capitalizes the first letter of each word and lowercases the rest, so mixed input comes out consistent.

Example
<?php
$text = "mary had a Little lamb";
echo mb_convert_case($text, MB_CASE_UPPER, "UTF-8"), PHP_EOL;
echo mb_convert_case($text, MB_CASE_TITLE, "UTF-8"), PHP_EOL;
Output
MARY HAD A LITTLE LAMB
Mary Had A Little Lamb

Example 2: non-ASCII text and case folding

Title mode handles accented letters. Full upper-casing can change the length of a string: the German ß becomes SS. Folding produces a form meant for case-insensitive comparison, so Straße folds to strasse.

Example
<?php
$result = [
    "title" => mb_convert_case("éCOLE nORMALE", MB_CASE_TITLE, "UTF-8"),
    "upper" => mb_convert_case("Straße", MB_CASE_UPPER, "UTF-8"),
    "fold" => mb_convert_case("Straße", MB_CASE_FOLD, "UTF-8"),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"title":"École Normale","upper":"STRASSE","fold":"strasse"}

Example 3: an invalid encoding

Because PHP 8 throws on an unknown encoding name, you can catch the error when the encoding comes from configuration or user input.

Example
<?php
try {
    mb_convert_case("abc", MB_CASE_UPPER, "not-an-encoding");
} catch (ValueError $e) {
    echo get_class($e), PHP_EOL;
}
Output
ValueError

Edge cases

  • Length can change. Full modes may turn one character into several, as with ß becoming SS. Do not assume the result has the same number of characters as the input.
  • Full versus simple modes. The _SIMPLE modes use one-to-one character mappings, while the full modes can apply special multi-character rules. Choose the simple variants when you need a conversion that keeps the character count.
  • Title case is not a grammar tool. MB_CASE_TITLE lowercases the rest of each word. Acronyms such as NASA become Nasa, and it does not know which small words an editor would leave lowercase. Test names containing apostrophes or hyphens against your own expectations before relying on them.
  • Folding is for comparing. MB_CASE_FOLD output is intended for matching, not for showing to users.
  • Empty strings are returned unchanged as empty strings.

Common mistakes

  1. Using strtoupper() on UTF-8 text. The single-byte functions are not designed for multibyte characters, so accented text may not convert as you expect.
  2. Relying on the internal encoding. If $encoding is omitted, the result depends on the mbstring configuration. Pass "UTF-8" when your data is UTF-8.
  3. Forgetting the mode argument. Unlike many PHP parameters, $mode is required.
  4. Checking for false. Modern PHP throws a ValueError rather than returning false for a bad encoding.
  5. Comparing display-cased strings. To compare text without regard to case, convert both sides with the same fold mode rather than comparing title-cased output.
  6. Feeding it invalid bytes. Strings that are not valid in the declared encoding can give unexpected output. Validate or convert input first.
  • mb_strtolower() and mb_strtoupper() are shorter forms for plain lower and upper conversion.
  • strtolower() and strtoupper() are the single-byte counterparts.
  • ucfirst() and ucwords() capitalize the first character of a string or of each word, but they are not multibyte aware.

Recap

Use mb_convert_case() when you need Unicode-aware casing with a choice of modes. Pass the encoding explicitly, choose a simple mode when the character count must stay the same, use folding for comparisons, and catch ValueError when the encoding name is not trusted.

Tested examples

Upper and title case conversion
<?php
$text = "mary had a Little lamb";
echo mb_convert_case($text, MB_CASE_UPPER, "UTF-8"), PHP_EOL;
echo mb_convert_case($text, MB_CASE_TITLE, "UTF-8"), PHP_EOL;
Output
MARY HAD A LITTLE LAMB
Mary Had A Little Lamb
Non-ASCII text and case folding
<?php
$result = [
    "title" => mb_convert_case("éCOLE nORMALE", MB_CASE_TITLE, "UTF-8"),
    "upper" => mb_convert_case("Straße", MB_CASE_UPPER, "UTF-8"),
    "fold" => mb_convert_case("Straße", MB_CASE_FOLD, "UTF-8"),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), PHP_EOL;
Output
{"title":"École Normale","upper":"STRASSE","fold":"strasse"}
Invalid encoding throws ValueError
<?php
try {
    mb_convert_case("abc", MB_CASE_UPPER, "not-an-encoding");
} catch (ValueError $e) {
    echo get_class($e), PHP_EOL;
}
Output
ValueError