mb_strrchr

Returns the part of a string from the last occurrence of a substring onward.

Signature
mb_strrchr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false
  • Added in PHP 5.2.0

Parameters

ParameterTypeDescription
$haystackstringThe string to search in.
$needlestringThe string to find. Unlike strrchr(), the whole needle is matched.
$before_needleoptionalbool= falseWhen true, returns everything before the last match instead of everything from it onward.
$encodingoptional?string= nullCharacter encoding. Null uses the internal encoding.

Return value

string|falseThe portion of the haystack from (or before) the last match, or false if the needle is not found.

Errors

Throws a ValueError if encoding is not a valid encoding.

Changelog

  • PHP 8.0.0needle now accepts an empty string.
  • PHP 8.0.0encoding is nullable now.

mb_strrchr() scans backwards for the needle and returns the tail of the string starting at that last match, needle included. With before_needle set to true you get the head instead, up to but not including the match.

The difference from strrchr

This is the real reason to know the function. strrchr() ignores everything after the first character of the needle — strrchr($s, '.tar') actually searches for .. mb_strrchr() matches the entire needle, so multi-character delimiters work the way you would expect. That alone makes it worth using even on ASCII input.

When to reach for it

Anything where the last delimiter is the interesting one: pulling a file extension off a name, taking the final segment of a path, splitting a namespaced class name at the last separator, or grabbing the value after the last colon in a log line. Because it returns a slice rather than an offset, you skip the offset arithmetic that mb_strrpos() would require.

What trips people up

The result keeps the delimiter, so extracting a clean extension or segment usually needs an mb_substr($result, 1) afterwards. And a needle that is absent returns false, not an empty string.

Example

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

When to use it

  • Take the final segment of a path or a namespaced class name
  • Pull the file extension off a filename that may contain non-ASCII characters
  • Grab the value after the last delimiter in a log or config line
  • Split a string at a multi-character delimiter that strrchr cannot handle

Frequently asked questions

What is the difference between mb_strrchr and strrchr?

strrchr only uses the first character of the needle and works on bytes; mb_strrchr matches the complete needle and is encoding-aware. For multi-character delimiters they give genuinely different answers.

How do I get the text after the last slash without the slash?

Wrap the call: mb_substr(mb_strrchr($path, '/'), 1). mb_strrchr always includes the needle in its result, so you trim it off yourself.

Is there a case-insensitive version of mb_strrchr?

Yes, mb_strrichr does the same search with Unicode case folding applied. Both take the same before_needle and encoding arguments.

More examples

Whole-needle matching versus strrchr

mb_strrchr finds the literal '.tar' and returns '.tar.gz'. strrchr throws away everything after the first character of the needle, searches for '.', and returns '.gz'. The comparison prints false, which is the whole point.

Example · php
<?php
mb_internal_encoding('UTF-8');
$name = 'backup.2026.tar.gz';

echo mb_strrchr($name, '.tar'), "\n";
echo strrchr($name, '.tar'), "\n";
var_dump(mb_strrchr($name, '.tar') === strrchr($name, '.tar'));

Last segment of a namespaced name

before_needle gives the namespace 'App\Modèles' and the default form gives '\Utilisateur', which mb_substr trims to 'Utilisateur'. The last dump shows false for a name with no separator, so guard with !== false before slicing.

Example · php
<?php
mb_internal_encoding('UTF-8');
$class = 'App\\Modèles\\Utilisateur';

echo mb_strrchr($class, '\\', true), "\n";        // namespace
echo mb_substr(mb_strrchr($class, '\\'), 1), "\n"; // short name
var_dump(mb_strrchr('Utilisateur', '\\'));

Discussion

  • Be the first to comment on this lesson.