mb_strrchr
Returns the part of a string from the last occurrence of a substring onward.
mb_strrchr(string $haystack, string $needle, bool $before_needle = false, ?string $encoding = null): string|false- Added in PHP 5.2.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$haystack | string | The string to search in. |
$needle | string | The string to find. Unlike strrchr(), the whole needle is matched. |
$before_needleoptional | bool= false | When true, returns everything before the last match instead of everything from it onward. |
$encodingoptional | ?string= null | Character 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
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.
<?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.
<?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