Str::is

Determines whether a string matches a wildcard pattern, or any pattern from an array.

Signature
Str::is(string|iterable<string> $pattern, string $value, bool $ignoreCase = false): bool

Parameters

ParameterTypeDescription
$$patternstring|iterable<string>A single pattern, or any iterable of patterns. Asterisks act as wildcards; every other character is matched literally.
$$valuestringThe string being tested. Note that it is the SECOND argument, not the first.
$$ignoreCaseoptionalbool= falseWhen true, the comparison is performed case-insensitively.

Return value

booltrue if $value matches at least one pattern; false otherwise. Patterns are anchored at both ends, and an asterisk matches any run of characters including none.

Errors

Nothing. Patterns are regex-quoted internally, so special characters in a pattern cannot break the match or inject a regex.

Str::is compiles each pattern into an anchored regular expression: the pattern is preg_quote()d, then \* is replaced with .*. Everything except the asterisk is therefore literal, and the match must cover the whole value — this is glob-like matching, not a substring test and not a regex.

When to reach for it

Use it for permission and routing style checks where users or config authors write the patterns: 'admin/*', '*.jpg', 'orders.*.created'. Because patterns are quoted before compilation, a config value containing ., ( or + is matched literally and cannot inject a regex — which is exactly why it is safe to expose to non-developers. It is what Laravel's own $request->is() and route pattern matching are built on.

What trips people up

The argument order is reversed from almost everything else: the pattern comes first, the subject second. Str::is($value, $pattern) compiles silently and returns wrong answers.

* is the only wildcard. ? is matched literally, so Str::is('user/?', 'user/4') is false. And because * becomes .* with the s modifier, it crosses slashes and newlines: 'users/*' also matches 'users/42/orders/7'. Anchor more tightly if you meant one segment.

Example

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

When to use it

  • Check a request path or route name against a wildcard permission pattern from config.
  • Match a filename against a list of accepted extension patterns, case-insensitively.
  • Test an event name such as orders.42.created against a subscriber's pattern.

Frequently asked questions

What order do the arguments go in for Str::is?

Pattern first, subject second: Str::is('foo*', 'foobar'). This is the reverse of str_contains() and swapping them fails silently rather than erroring.

Does Str::is support regular expressions?

No. The pattern is preg_quote()d first, so only '*' acts as a wildcard and every other character — including . ? and + — is matched literally.

Why does 'users/*' match a longer path in Str::is?

Because '*' compiles to '.*', which matches slashes and newlines too. Write the literal segments you expect, such as 'users/*/orders/*', or use a real regex for single-segment matching.

More examples

Permission patterns from config

The dots in the patterns are matched literally because Str::is quotes the pattern before compiling it. A hand-rolled preg_match would have treated each dot as "any character" and matched users.delete against users.view.

Example · php
<?php

use Illuminate\Support\Str;

// Written by an administrator, not a developer.
$allowed = ['reports.*', 'users.view', 'billing.invoice.*'];

$abilities = [
    'reports.export',
    'users.view',
    'users.delete',
    'billing.invoice.download',
];

foreach ($abilities as $ability) {
    printf("%-26s %s\n", $ability, var_export(Str::is($allowed, $ability), true));
}

// reports.export             true
// users.view                 true
// users.delete               false
// billing.invoice.download   true

Segment-safe matching

The first assertion is the surprise: 'users/*' matches a four-segment path. Adding the literal segments you expect keeps the pattern honest; when you genuinely need "one segment and no more", fall back to a real regex.

Example · php
<?php

use Illuminate\Support\Str;

$path = 'users/42/orders/7';

// Too loose: '*' becomes '.*' and crosses every slash.
var_dump(Str::is('users/*', $path));        // true

// Anchoring the shape you actually mean.
var_dump(Str::is('users/*/orders/*', $path)); // true
var_dump(Str::is('users/*', 'users/42'));     // true

// If you need exactly one segment, Str::is is the wrong tool.
var_dump((bool) preg_match('#^users/[^/]+$#', $path)); // false

Discussion

  • Be the first to comment on this lesson.