Strings7 min readExamples run on PHP 8.5.10

strrchr()

Learn how PHP 8.4 strrchr() returns the part of a string starting at the last occurrence of a character, with examples, edge cases and common mistakes.

Signature

strrchr(string $haystack, string $needle, bool $before_needle = false): string|false

Purpose

strrchr() finds the last occurrence of a character in a string and returns the part of the string from that character to the end. It is a compact way to grab things like a file extension, the last path segment or the text after the final separator in a value.

The name hints at the behavior: the r stands for "reverse" search. Its sibling strstr() works from the left; strrchr() works from the right.

Signature

Parameters and defaults

  • $haystack is the string to search.
  • $needle is the character to look for. If it has more than one character, only the first one is used. This differs from strstr(), which matches the whole needle. Since PHP 8.0.0 an empty string is accepted as a needle, and passing an integer is no longer supported; pass a string, or use chr() if you have a character code.
  • $before_needle defaults to false. When true, the function returns the part of the haystack before the last occurrence, without the needle itself. This parameter was added in PHP 8.3.0.

Return value and failure

The function returns a string, or false when the needle is not found. It does not throw for a missing match, so you must check the result yourself. The search is case-sensitive and binary-safe.

Example 1: extracting an extension

The default mode keeps the needle at the start of the result, so you usually remove it with substr().

Example
<?php
$path = 'archive/report.final.txt';
$ext = strrchr($path, '.');
echo json_encode([
    'with_dot' => $ext,
    'extension' => substr($ext, 1),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"with_dot":".txt","extension":"txt"}

Because the search starts from the right, only the final dot matters, even though the name contains two.

Example 2: splitting a path with before_needle

With the third argument set to true you get the leading part instead.

Example
<?php
$path = '/var/www/app/index.php';
$file = strrchr($path, '/');
$dir = strrchr($path, '/', true);
echo json_encode([
    'file' => substr($file, 1),
    'dir' => $dir,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"file":"index.php","dir":"/var/www/app"}

For real filesystem paths, basename(), dirname() and pathinfo() are usually more suitable, but this pattern is useful for URL-like or custom identifiers.

Example 3: only the first needle character counts

Example
<?php
$text = 'a-b--c';
echo json_encode([
    'last_dash' => strrchr($text, '--'),
    'first_match' => strstr($text, '--'),
    'missing' => strrchr($text, 'x'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"last_dash":"-c","first_match":"--c","missing":false}

The needle -- is reduced to -, so strrchr() returns from the last dash. strstr() matches the full two-character text from the left. A missing character produces false.

Edge cases

  • Needle at the end: strrchr('file.', '.') returns ".", a non-empty string.
  • Needle at the start with before_needle: the result is an empty string "", which is different from false.
  • Falsy strings: a successful result can be "0", which PHP treats as false in a boolean context. Compare with === false rather than relying on truthiness.
  • Case sensitivity: strrchr('ABC', 'b') does not match.
  • Bytes, not characters: the function works on bytes. A multibyte character used as a needle contributes only its first byte, so do not use it for reliable multibyte searching.

Common mistakes

  1. Expecting a full-substring search. Only the first needle character is used. For a multi-character search from the right, use strrpos() together with substr().
  2. Forgetting the needle is included. In the default mode the result starts with the needle, so a dot or slash is still there.
  3. Testing the result with if ($result). Empty and "0" results are falsy; use a strict comparison with false.
  4. Passing an integer needle. Integers are not supported in PHP 8; convert to a string or use chr().
  5. Using before_needle on older runtimes. The parameter exists from PHP 8.3.0, which includes PHP 8.4.
  • strstr() returns the part of a string from the first occurrence of a whole substring.
  • strrpos() returns the position of the last occurrence of a substring rather than the text.
  • substr() trims the result, for example to drop the leading separator.
  • basename(), dirname() and pathinfo() handle path-specific tasks.

Recap

strrchr() searches from the right for one character and returns the tail of the string beginning there, or the head before it when before_needle is true. It returns false when nothing matches, uses only the first byte of the needle and is case-sensitive. Always check the result strictly, and remember to strip the needle when you only want the text after it.

Tested examples

Extract a file extension with and without the dot
<?php
$path = 'archive/report.final.txt';
$ext = strrchr($path, '.');
echo json_encode([
    'with_dot' => $ext,
    'extension' => substr($ext, 1),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"with_dot":".txt","extension":"txt"}
Split a path using before_needle
<?php
$path = '/var/www/app/index.php';
$file = strrchr($path, '/');
$dir = strrchr($path, '/', true);
echo json_encode([
    'file' => substr($file, 1),
    'dir' => $dir,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"file":"index.php","dir":"/var/www/app"}
Only the first needle character is used
<?php
$text = 'a-b--c';
echo json_encode([
    'last_dash' => strrchr($text, '--'),
    'first_match' => strstr($text, '--'),
    'missing' => strrchr($text, 'x'),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"last_dash":"-c","first_match":"--c","missing":false}