Str::excerpt

Extracts a window of text around the first match of a phrase, with configurable radius and omission marker.

Signature
Str::excerpt(string $text, string $phrase = '', array $options = []): ?string

Parameters

ParameterTypeDescription
$$textoptionalstring= nullThe full text to extract an excerpt from.
$$phraseoptionalstring= ''The phrase to centre the excerpt on. Matched case-insensitively, but reproduced in the excerpt with the original casing from $text.
$$optionsoptionalarray= []Accepts 'radius' (int, default 100) for the number of characters kept on each side, and 'omission' (string, default '...') for the marker prepended and appended where text was trimmed.

Return value

?stringThe matched phrase surrounded by up to $radius characters of context on each side, with the omission marker prepended and appended where text was cut. Returns null when the phrase is not found.

Errors

Nothing, but the return type is nullable — a missed phrase produces null, not an exception.

Str::excerpt finds the first occurrence of $phrase, keeps up to radius characters either side of it, and marks each trimmed edge with omission. It is the keyword-in-context snippet you see under a search result.

When to reach for it

Use it to show why a record matched: a snippet of an article body around the search term, the relevant line of a long log entry, the sentence in a document that mentions a name. It is far better than a blind Str::limit(), which usually truncates before the interesting part.

What trips people up

The return type is nullable. When the phrase is absent you get null — not the original text, not an empty string. Echoing it renders nothing, and assigning it to a string-typed property throws a TypeError. Always coalesce: Str::excerpt($body, $q) ?? Str::limit($body, 150).

Matching is case-insensitive (the internal pattern uses the i flag) even though the docs do not say so, and the excerpt reproduces the casing found in $text, not the casing you searched with. The omission marker is only added on a side that was actually cut, so a short text can come back with no markers at all. Radius counts characters, not words, so the excerpt will cut mid-word.

Example

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

When to use it

  • Render the matching snippet under each result on a search page.
  • Pull the relevant portion of a long log line around an error code.
  • Build an email preview centred on a recipient's name rather than the first 100 characters.

Frequently asked questions

Why does Str::excerpt return null?

Because the phrase was not found in the text. It returns null rather than the original string, so coalesce with a fallback such as Str::limit().

Is the Str::excerpt phrase match case sensitive?

No. The internal regex uses the case-insensitive flag, so searching 'MY' matches 'my' — and the excerpt reproduces the casing as it appears in the original text.

How do I change the ... marker in Str::excerpt?

Pass an 'omission' key in the options array, for example ['radius' => 40, 'omission' => '… ']. It is only added on a side that was actually trimmed.

More examples

Search result snippets with a safe fallback

The first call centres 40 characters either side of "Stringable" and wraps the cut edge in '...'. The second finds nothing, excerpt returns null, and the ?? falls back to a plain leading truncation — without that fallback the second result would render as an empty line.

Example · php
<?php

use Illuminate\Support\Str;

$body = 'Laravel ships a fluent string builder. The Str class exposes '
      . 'dozens of helpers for slicing, casing and testing strings, and '
      . 'every one of them is also available on the Stringable object.';

function snippet(string $body, string $query): string
{
    return Str::excerpt($body, $query, ['radius' => 40])
        ?? Str::limit($body, 80);
}

echo snippet($body, 'Stringable'), "\n\n";
echo snippet($body, 'Vue'), "\n";

Using excerpt as a match-aware truncator

The first call isolates the duplicate-key detail from a log line too long for a dashboard cell. The second shows the edge case of an empty phrase: the match is zero-length at position 0, so you get the first 45 characters with the omission marker appended.

Example · php
<?php

use Illuminate\Support\Str;

$log = '[2026-01-04 09:00:00] production.ERROR: SQLSTATE[23000]: '
     . 'Integrity constraint violation: 1062 Duplicate entry '
     . "'[email protected]' for key 'users_email_unique'";

echo Str::excerpt($log, 'Duplicate entry', [
    'radius'   => 30,
    'omission' => '… ',
]), "\n";

// An empty phrase turns it into a plain head-truncator.
echo Str::excerpt($log, '', ['radius' => 45]), "\n";

Discussion

  • Be the first to comment on this lesson.