Str::lower

Converts a string to lowercase, handling accented and non-Latin characters that strtolower ignores.

Signature
Str::lower(string $value): string

Parameters

ParameterTypeDescription
$$valuestringThe string to lowercase. An empty string returns an empty string.

Return value

stringThe string with every character that has a lowercase mapping converted, using UTF-8.

Str::lower is mb_strtolower with the encoding pinned to UTF-8. That pinning is the whole point: PHP's own strtolower has been ASCII-only and locale-independent since PHP 8.2, so it leaves É, Ä and every Cyrillic or Greek capital exactly as it found them.

When to reach for it

Any time case is being normalised rather than displayed: canonicalising an email address before a uniqueness check, building a cache key, comparing a user-supplied tag against a whitelist, or lowercasing a header name. If you skip it, two values that look identical to a user will hash and compare differently.

It is not locale-aware

The Unicode default mappings are applied regardless of the application locale. Turkish is the classic casualty: I lowercases to i, not the dotless ı, and İ becomes i followed by a combining dot — which makes the result longer than the input. Do not assume the output has the same character count as the input.

Lowercasing is not folding

For case-insensitive comparison of arbitrary Unicode, mb_convert_case($value, MB_CASE_FOLD) is the correct tool; lowercasing handles the common cases but not every equivalence, such as the German sharp s.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Normalise an email address or username before checking it against the database.
  • Build a case-insensitive cache key or lookup array key from user input.
  • Lowercase a header or query parameter name before matching it against a whitelist.

Frequently asked questions

Why does strtolower not lowercase accented characters in PHP?

Since PHP 8.2 strtolower only maps the ASCII range A–Z and ignores the locale, so bytes above 0x7F are left untouched. Str::lower calls mb_strtolower with UTF-8, which applies the full Unicode mapping.

Does Str::lower respect the application locale?

No. It always applies the Unicode default mappings, so Turkish and Azerbaijani dotted and dotless i are handled the same way as in English. Use an intl Transliterator if you need locale-specific casing.

Should I use Str::lower for case-insensitive comparison?

It is fine for ASCII and most European text, but mb_convert_case($value, MB_CASE_FOLD, 'UTF-8') is the correct operation for arbitrary Unicode because it also resolves equivalences such as ß and ss.

More examples

Canonicalising an email before a lookup

The mutator stores one canonical form and the query lowercases the incoming value the same way, so '[email protected]' and '[email protected]' cannot become two accounts. Requires a booted application with a database connection.

Example · php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

class User extends Model
{
    protected function email(): Attribute
    {
        return Attribute::make(
            set: fn (string $value) => Str::lower(trim($value)),
        );
    }
}

// Anywhere else in the application:
$user = User::firstWhere('email', Str::lower($request->input('email')));

Lowercasing is not case folding

Lowercasing maps each character to its lowercase form; case folding also resolves equivalences such as ß to ss. When you are comparing rather than displaying, folding is the more correct operation.

Example · php
<?php

use Illuminate\Support\Str;

$a = 'STRASSE';
$b = 'straße';

var_dump(Str::lower($a) === Str::lower($b));
// bool(false)  — 'strasse' vs 'straße'

var_dump(
    mb_convert_case($a, MB_CASE_FOLD, 'UTF-8')
    === mb_convert_case($b, MB_CASE_FOLD, 'UTF-8')
);
// bool(true)

Discussion

  • Be the first to comment on this lesson.