as of 2019-11-18, it seems nobody on stackoverflow got this right, here's how mb_ucfirst() should be implemented in userland:
For PHP>=8.0.0:
function mb_ucfirst(string $str, ?string $encoding = null): string
{
return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding) . mb_substr($str, 1, null, $encoding);
}
For PHP >= 7.0.0:
function mb_ucfirst(string $str, string $encoding = null): string
{
if ($encoding === null) {
$encoding = mb_internal_encoding();
}
return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding) . mb_substr($str, 1, null, $encoding);
}
For PHP>=5.1.0:
function mb_ucfirst($str, $encoding = null)
{
if (!is_string($str)) {
throw new InvalidArgumentException("Argument 1 must be string, " . gettype($str) . " given");
}
if ($encoding === null) {
$encoding = mb_internal_encoding();
} elseif (!is_string($encoding)) {
throw new InvalidArgumentException("Argument 2 must be string|null, " . gettype($encoding) . " given");
}
return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding) . mb_substr($str, 1, null, $encoding);
}