Str::substr

Returns a portion of a string by character offset, safely handling multibyte text.

Signature
Str::substr(string $string, int $start, ?int $length = null, string $encoding = 'UTF-8'): string
  • Added in Laravel 5.2

Parameters

ParameterTypeDescription
$$stringstringThe string to slice.
$$startintZero-based character offset to start at. A negative value counts back from the end of the string.
$$lengthoptionalint|null= nullNumber of characters to return. null runs to the end of the string; a negative value stops that many characters before the end.
$$encodingoptionalstring= 'UTF-8'Character encoding passed through to mb_substr.

Return value

stringThe requested portion of the string, or an empty string when the range falls outside it.

Changelog

  • PHP 8.xPHP 8 made mb_substr return an empty string instead of false for an out-of-range start, so this method no longer returns false under any input.

Str::substr is a thin wrapper over mb_substr with UTF-8 as the default encoding. That single default is the reason to use it: PHP's plain substr counts bytes, so slicing accented or CJK text at an arbitrary offset splits a character in half and produces mojibake or invalid UTF-8 that a JSON encode will later reject.

Reach for it whenever the offsets are meaningful to a human — the last four digits of a card number, a fixed-width column from a legacy export, an initial for an avatar, a prefix you already located with Str::startsWith.

What trips people up

  • Offsets are characters, not bytes, and not grapheme clusters either. An emoji with a skin-tone modifier or a combining accent still counts as more than one character, so a naive slice can separate a base letter from its accent.
  • A negative $length is an end offset, not a count: Str::substr('abcdef', 1, -2) is bcd.
  • An out-of-range start returns '', never false, so an === false check will never fire.
  • For truncating display text, Str::limit and Str::words are almost always the better tool because they add an ellipsis and avoid cutting mid-word.

Example

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

When to use it

  • Show only the last four digits of a card or account number in a receipt.
  • Pull fixed-width fields out of a legacy flat-file export.
  • Take the first character of a name for an avatar placeholder without corrupting non-Latin scripts.

Frequently asked questions

What is the difference between Str::substr and PHP's substr?

Str::substr counts characters using mb_substr with UTF-8 by default, while substr counts bytes. On any text containing accents, CJK characters or emoji, substr can split a character in half and produce invalid UTF-8.

Does Str::substr ever return false?

No. An out-of-range start produces an empty string, so checking the result with === false will never be true; test for an empty string instead.

How do I get the last N characters of a string?

Pass a negative start with no length: Str::substr($value, -4) returns the final four characters. Use Str::mask instead if the goal is to hide the rest rather than extract the tail.

More examples

Masking and excerpting

The first two lines both print ************1234, showing that Str::mask is the clearer choice when the goal is redaction rather than extraction. The dump is "日本語" — three characters, nine bytes — and Str::length reports 7 for the full string, confirming that both helpers count characters while strlen() would report 21.

Example · php
<?php

use Illuminate\Support\Str;

$card = '4111111111111234';

echo str_repeat('*', 12).Str::substr($card, -4), PHP_EOL;

// Str::mask does the same job in one call.
echo Str::mask($card, '*', 0, 12), PHP_EOL;

// Slicing non-Latin text stays valid.
var_dump(Str::substr('日本語テキスト', 0, 3));
var_dump(Str::length('日本語テキスト'));

Parsing a fixed-width record

Prints id 123, name "José Álvarez" and amount 425.5. Using Str::substr rather than substr is essential here: the accented characters make the byte offsets and character offsets diverge, so plain substr would return a truncated name and shift the amount field. Str::squish cleans the padding spaces from the fixed-width column.

Example · php
<?php

use Illuminate\Support\Str;

// cols 0-5 id, 6-25 name, 26-33 amount
$line = '000123José Álvarez        00042550';

$record = [
    'id'     => (int) Str::substr($line, 0, 6),
    'name'   => Str::squish(Str::substr($line, 6, 20)),
    'amount' => (int) Str::substr($line, 26, 8) / 100,
];

print_r($record);

Discussion

  • Be the first to comment on this lesson.