Multibyte strings7 min readExamples run on PHP 8.5.10

mb_lcfirst()

Learn how PHP 8.4 mb_lcfirst() lowercases only the first character of a string using a character encoding, with examples, edge cases and mistakes.

Signature

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

Purpose

mb_lcfirst() returns a copy of a string in which the first character is converted to lowercase. It is the multibyte-aware counterpart of lcfirst(). It was added in PHP 8.4 and belongs to the mbstring extension, so that extension must be enabled.

The word character matters. In UTF-8, a letter such as É takes more than one byte. A byte-oriented function cannot reliably treat it as a single unit, while mb_lcfirst() reads the string using a character encoding and changes the whole first character.

Signature

Parameters and defaults

  • $string: the input string. Only its first character is considered; the rest is copied unchanged.
  • $encoding: the character encoding of the string, such as "UTF-8". If you omit it or pass null, PHP uses the current internal encoding of the mbstring extension.

Passing the encoding explicitly makes the code independent of global configuration, which is useful in libraries and in code that other people will copy.

Return value and failure cases

The function always returns a string. If the first character has no lowercase form (a digit, a space, punctuation, or a character that is already lowercase), the result is the same as the input. An empty string produces an empty string.

If you pass an encoding name that mbstring does not recognise, PHP throws a ValueError. Wrap dynamic encoding names in a try/catch block if they come from outside your program.

Example 1: multibyte versus ASCII-only

The first example compares mb_lcfirst() with plain lcfirst() on a word that begins with an accented capital letter. Plain lcfirst() does not handle this letter as a multibyte character, so it leaves the word unchanged, while mb_lcfirst() lowers it.

Example
<?php
$word = "Élan";
echo json_encode([mb_lcfirst($word, "UTF-8"), lcfirst($word)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["élan","Élan"]

Example 2: mapping over a list

Because the function takes a string and returns a string, it fits naturally into array_map(). The list below includes an empty string and a value starting with a digit to show that neither causes trouble.

Example
<?php
$labels = ["Ärger", "Öl", "Zebra", "", "123Abc"];
$result = array_map(fn(string $s): string => mb_lcfirst($s, "UTF-8"), $labels);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["ärger","öl","zebra","","123Abc"]

Example 3: only the first character changes

This example shows that the rest of the string is left alone, and that an invalid encoding name raises a ValueError.

Example
<?php
$result = mb_lcfirst("ÉCOLE", "UTF-8");
try {
    mb_lcfirst("Abc", "not-an-encoding");
    $error = "none";
} catch (ValueError $e) {
    $error = get_class($e);
}
echo json_encode([$result, $error], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["éCOLE","ValueError"]

Edge cases

  • Empty input: returns "".
  • No lowercase form: digits, punctuation and whitespace at the start are returned unchanged.
  • Already lowercase: the string is returned as it was.
  • Leading whitespace: if the string begins with a space, the first character is the space, so nothing is lowercased. Trim first if that is not what you want.
  • Wrong encoding: if the bytes are not valid in the declared encoding, the result may not be meaningful. Make sure the encoding matches the actual data.

Common mistakes

  1. Expecting the whole string to change. mb_lcfirst() is not mb_strtolower(). If you need every character lowercased, use mb_strtolower().
  2. Using lcfirst() on UTF-8 text. It works on bytes, so it will not lower a non-ASCII first letter such as É.
  3. Relying on the default encoding. If the internal encoding is changed elsewhere, your output can change too. Pass "UTF-8" explicitly when you know the data is UTF-8.
  4. Forgetting that the function returns a new string. The original variable is not modified; assign the result.
  5. Passing untrusted encoding names. An unknown name throws ValueError, so validate such input first.
  • mb_ucfirst(): makes the first character uppercase, the opposite operation.
  • lcfirst(): the byte-based version of this operation.
  • mb_strtolower(): lowercases an entire multibyte string.
  • mb_substr(): extracts characters by position when you need custom logic.

Recap

Use mb_lcfirst($string, "UTF-8") when you want to lowercase just the first character of text that may contain non-ASCII letters. It returns a string, leaves everything after the first character untouched, returns empty input as empty, and throws ValueError for unknown encoding names.

Tested examples

mb_lcfirst() versus lcfirst() on an accented capital
<?php
$word = "Élan";
echo json_encode([mb_lcfirst($word, "UTF-8"), lcfirst($word)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["élan","Élan"]
Mapping mb_lcfirst() over a list
<?php
$labels = ["Ärger", "Öl", "Zebra", "", "123Abc"];
$result = array_map(fn(string $s): string => mb_lcfirst($s, "UTF-8"), $labels);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["ärger","öl","zebra","","123Abc"]
Only the first character changes; invalid encoding throws
<?php
$result = mb_lcfirst("ÉCOLE", "UTF-8");
try {
    mb_lcfirst("Abc", "not-an-encoding");
    $error = "none";
} catch (ValueError $e) {
    $error = get_class($e);
}
echo json_encode([$result, $error], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["éCOLE","ValueError"]