Str::snake

Converts a camelCase or spaced string to snake_case with a configurable delimiter.

Signature
Str::snake(string $value, string $delimiter = '_'): string
  • Added in Laravel 4.0

Parameters

ParameterTypeDescription
$$valuestringThe string to convert. A value that is already entirely lowercase is returned unchanged.
$$delimiteroptionalstring= '_'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, HTTPResponse becomes h_t_t_p_response and XMLHttpRequest becomes x_m_l_http_request. Normalise acronyms before converting, or maintain an explicit mapping.
  • A digit followed by a capital also splits, so user2FA becomes user2_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')) is h_t_t_p_response, not the original.

Example

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

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.

Example · php
<?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.

Example · php
<?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

  • Be the first to comment on this lesson.