Str::is
Determines whether a string matches a wildcard pattern, or any pattern from an array.
Str::is(string|iterable<string> $pattern, string $value, bool $ignoreCase = false): boolParameters
| Parameter | Type | Description |
|---|---|---|
$$pattern | string|iterable<string> | A single pattern, or any iterable of patterns. Asterisks act as wildcards; every other character is matched literally. |
$$value | string | The string being tested. Note that it is the SECOND argument, not the first. |
$$ignoreCaseoptional | bool= false | When 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
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.
<?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 trueSegment-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.
<?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