mb_lcfirst
Lowercases the first character of a string using Unicode case mapping, leaving the rest unchanged.
mb_lcfirst(string $string, ?string $encoding = null): string- Added in PHP 8.4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$string | string | The input string. |
$encodingoptional | ?string= null | The character encoding of the string. If omitted or null, the internal encoding is used. |
Return value
stringThe string with its first character lowercased; all other characters are returned unchanged.
Errors
Throws a ValueError if encoding is not a name mbstring recognises.
mb_lcfirst() arrived in PHP 8.4 to close a long-standing gap. lcfirst() operates on the first byte, so for any string beginning with a non-ASCII letter it does nothing at all — lcfirst('Ärger') returns Ärger unchanged, and it does so silently, with no warning and no error. That is the kind of bug that survives code review and shows up in production text.
The typical use is mechanical string shaping rather than prose: deriving a camelCase identifier or JSON key from a class name or a human label, or undoing a title-cased column heading. It is the exact inverse of mb_ucfirst(), and the two are usually introduced into a codebase together.
Only the first character is touched. mb_lcfirst('ÉCOLE') gives éCOLE, not école — if you want the whole string lowercased, that is mb_strtolower(). Chaining mb_lcfirst(mb_convert_case($s, MB_CASE_TITLE)) is the usual recipe for lowerCamelCase.
An empty string comes back as an empty string, so no guard is needed. Note also that some characters have no lowercase form; those are simply returned as they are, which is correct behaviour rather than a failure.
Example
When to use it
- Derive a lowerCamelCase property name from a human-readable label containing accents.
- Convert a title-cased CSV column heading into a JSON key.
- Undo the first-letter capitalisation applied by mb_ucfirst() elsewhere in a pipeline.
- Normalise the first letter of a tag or slug before comparison.
Frequently asked questions
What is the difference between lcfirst and mb_lcfirst?
lcfirst() lowercases the first byte, so it silently does nothing when a string starts with a multi-byte character such as Ä or É. mb_lcfirst() lowercases the first character using Unicode case mapping, whatever its byte length.
Which PHP version added mb_lcfirst?
PHP 8.4.0, alongside mb_ucfirst(), mb_trim(), mb_ltrim() and mb_rtrim(). On earlier versions, combine mb_strtolower() with mb_substr() to get the same result.
Does mb_lcfirst lowercase the whole string?
No, it changes only the first character and returns everything after it untouched. Use mb_strtolower() when you want the entire string lowercased.
More examples
Build lowerCamelCase keys from labels
Title-casing then removing spaces gives ÜberUns, ÉtageZéro and SimpleCase; mb_lcfirst() turns each into lowerCamelCase. With plain lcfirst() the first two would keep their capital Ü and É, because those letters do not fit in a single byte.
<?php
$labels = ['Über Uns', 'Étage Zéro', 'Simple Case'];
foreach ($labels as $label) {
$studly = str_replace(' ', '', mb_convert_case($label, MB_CASE_TITLE, 'UTF-8'));
echo mb_lcfirst($studly, 'UTF-8'), "\n";
}Only the first character changes
The first line lowercases only the É, leaving the shouting intact. The second lowercases everything. The third title-cases first and then drops the leading letter, which is the combination you normally want when reformatting all-caps data entry.
<?php
$s = "ÉCOLE NORMALE";
echo mb_lcfirst($s, 'UTF-8'), "\n";
echo mb_strtolower($s, 'UTF-8'), "\n";
echo mb_lcfirst(mb_convert_case($s, MB_CASE_TITLE, 'UTF-8'), 'UTF-8'), "\n";A pre-8.4 fallback
The manual version splits off the first character, lowercases it and reattaches the remainder; var_dump confirms it agrees with the built-in. Keep a shim like this if you support PHP 8.3, but drop it once you can rely on 8.4, since the built-in is both faster and clearer.
<?php
function lcfirstMb(string $s, string $enc = 'UTF-8'): string {
if ($s === '') {
return $s;
}
return mb_strtolower(mb_substr($s, 0, 1, $enc), $enc) . mb_substr($s, 1, null, $enc);
}
$s = "Öffnungszeiten";
var_dump(lcfirstMb($s) === mb_lcfirst($s, 'UTF-8'));
echo lcfirstMb($s), "\n";
Discussion