Str::snake
Converts a camelCase or spaced string to snake_case with a configurable delimiter.
Str::snake(string $value, string $delimiter = '_'): string- Added in Laravel 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$$value | string | The string to convert. A value that is already entirely lowercase is returned unchanged. |
$$delimiteroptional | string= '_' | The string inserted between words. Passing '-' produces kebab-case and '.' produces dot.case. |
Return value
stringThe lowercased string with a delimiter inserted before each former capital letter and all whitespace removed.
Changelog
- PHP 5.xResults are memoised in a static cache keyed by value and delimiter, so repeated calls with the same input are free but a very large number of distinct inputs grows memory for the life of the process.
Str::snake inserts a delimiter in front of every capital letter, strips whitespace, and lowercases the result. The delimiter is the second argument rather than a fixed underscore, which is why the same method also produces kebab-case and dot.case — Str::kebab is literally a call to it with '-'.
Reach for it at boundaries: mapping a camelCase JSON payload onto database columns, deriving a config or translation key from a class name, generating data-* attribute names for a view.
What trips people up
- Acronyms shatter. Because every capital is a boundary,
HTTPResponsebecomesh_t_t_p_responseandXMLHttpRequestbecomesx_m_l_http_request. Normalise acronyms before converting, or maintain an explicit mapping. - A digit followed by a capital also splits, so
user2FAbecomesuser2_f_a. - An input that is already entirely lowercase short-circuits and is returned untouched, so
Str::snake('foo bar baz')works but a string of only lowercase letters and delimiters is never re-delimited. - It does not round-trip with
Str::studly:Str::snake(Str::studly('HTTP_response'))ish_t_t_p_response, not the original.
Example
When to use it
- Map an incoming camelCase API payload onto snake_case database columns before an insert.
- Build a dot.case config or translation key from a class or method name.
- Generate kebab-case CSS class names or data attributes from PHP identifiers.
Frequently asked questions
Why does Str::snake turn HTTPResponse into h_t_t_p_response?
Because the implementation inserts the delimiter before every capital letter with no special handling for consecutive capitals. Fold acronyms to a single leading capital first, or keep an explicit mapping for the identifiers you care about.
How do I get kebab-case or dot.case from Str::snake?
Pass the delimiter as the second argument: Str::snake('fooBar', '-') gives 'foo-bar' and Str::snake('fooBar', '.') gives 'foo.bar'. Str::kebab is simply this method called with a hyphen.
Is Str::snake the exact inverse of Str::studly?
No. studly() preserves existing capitals, so Str::snake(Str::studly('HTTP_response')) returns 'h_t_t_p_response' rather than the original string. Only inputs with no internal capitals round-trip reliably.
More examples
Normalising an API payload for the database
The printed keys are first_name, last_login_at and is_active — the exact column names Laravel's conventions expect, produced without a hand-written map. The final line prints "app.service.provider", showing the same method generating a config-style key.
<?php
use Illuminate\Support\Str;
$payload = [
'firstName' => 'Ada',
'lastLoginAt' => '2024-01-01',
'isActive' => true,
];
$row = [];
foreach ($payload as $key => $value) {
$row[Str::snake($key)] = $value;
}
print_r(array_keys($row));
// Dot case is the same call with a different delimiter.
echo Str::snake('AppServiceProvider', '.'), PHP_EOL;The acronym trap and a way around it
The first dump is "s_m_s_gateway_client", the delimiter-per-capital behaviour that surprises people. After folding runs of capitals down to a single leading capital the value becomes "SmsGatewayClient" and snake() then yields "sms_gateway_client". If you need this often, wrap it in a Str macro rather than repeating the regex.
<?php
use Illuminate\Support\Str;
// Naive conversion of an acronym-heavy class name.
var_dump(Str::snake('SMSGatewayClient'));
// Fix: fold acronyms to a single leading capital first.
$normalised = preg_replace_callback(
'/([A-Z]+)(?=[A-Z][a-z]|\b)/',
fn ($m) => ucfirst(strtolower($m[1])),
'SMSGatewayClient'
);
var_dump($normalised);
var_dump(Str::snake($normalised));
Discussion