Str::squish
Collapses every run of whitespace to one space and trims both ends of the string.
Str::squish(string $value): string- Added in Laravel 9.7
Parameters
| Parameter | Type | Description |
|---|---|---|
$$value | string | The string to normalise. Whitespace here means Unicode whitespace plus the Hangul filler characters U+3164 and U+1160. |
Return value
stringThe value with leading and trailing whitespace and invisible characters removed and every internal whitespace run reduced to a single space.
Changelog
- PHP 11.xU+1160 (Hangul Jungseong Filler) was added alongside U+3164 to the set of characters treated as whitespace.
- PHP 12.xEnd trimming now goes through Str::trim, which also strips a wider set of invisible characters such as U+200B rather than only U+FEFF.
Str::squish does the two things you almost always want together: trim the ends and collapse the middle. A single call turns " Senior\u{00A0}\u{00A0}PHP Engineer \n" into "Senior PHP Engineer".
Reach for it on anything a human typed or pasted — form fields, spreadsheet imports, scraped markup, CSV cells. Pasted text is full of non-breaking spaces and zero-width characters that trim() will not touch, which is why two values that look identical fail an equality check or produce duplicate rows.
What trips people up
- Plain
trim()only strips ASCII whitespace at the ends. A non-breaking space survives it and survivespreg_replace('/\s+/', ...)without theumodifier too.Str::squishhandles both. - Every run collapses to one ordinary space, including newlines. Deliberate line breaks in a textarea are destroyed, so do not squish content you intend to render as multiple lines.
- A string made entirely of whitespace becomes
'', not' '. Validate for emptiness after squishing, not before. - Zero-width characters are removed from the ends but a zero-width space sitting between two words is not collapsed.
Squishing before hashing, comparing or slugging is the cheapest way to stop invisible characters from creating duplicates.
Example
When to use it
- Normalise a name or title field on a form request before validating uniqueness.
- Clean cells from a pasted spreadsheet so that trailing non-breaking spaces do not create duplicate records.
- Flatten indented HTML or a multi-line string into a single line for logging.
Frequently asked questions
What is the difference between Str::squish and trim?
trim only removes whitespace from the two ends, while Str::squish also collapses every internal run to a single space and understands Unicode whitespace such as the non-breaking space that trim leaves behind.
Does Str::squish remove non-breaking spaces?
Yes. Its pattern uses the Unicode modifier, so U+00A0 and the Hangul filler characters U+3164 and U+1160 are treated as whitespace and collapsed like any other space.
Will Str::squish preserve line breaks in a textarea?
No. Newlines are whitespace and collapse into a single space along with everything else, so do not squish content that should keep its paragraphs; trim it or use a targeted regex instead.
More examples
Why trim() is not enough
trim() returns a 24-byte string that still contains the two non-breaking spaces and the run of ordinary spaces, so it will not compare equal to a clean "Senior PHP Engineer". Str::squish returns the 19-character clean value. The third line shows the usual pairing: squish first, then slug, so the slug is derived from normalised text.
<?php
use Illuminate\Support\Str;
$raw = " Senior\u{00A0}\u{00A0}PHP Engineer \n";
var_dump(trim($raw));
var_dump(Str::squish($raw));
var_dump(Str::slug(Str::squish($raw)));Normalising input in a form request
Squishing inside prepareForValidation means the unique rule compares the cleaned value, so "Acme\u{00A0}Ltd" and "Acme Ltd" are correctly rejected as duplicates instead of both being stored. Note that 'required' runs after the squish, so a field of only whitespace is now correctly seen as empty. This needs a booted application, so it is displayed rather than executed.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Str;
class StoreCompanyRequest extends FormRequest
{
protected function prepareForValidation(): void
{
$this->merge([
'name' => Str::squish((string) $this->input('name')),
]);
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255', 'unique:companies,name'],
];
}
}
Discussion